diff --git a/RELEASES.md b/RELEASES.md index 69b804cf24c40..7da73afb4111f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,102 @@ +Version 1.0.0-beta (April 2015) +------------------------------------- + +* ~1100 changes, numerous bugfixes + +* Highlights + + * The big news is that the vast majority of the standard library + is now `#[stable]` -- 75% of the non-deprecated API surface at + last count. Numerous crates are now running on stable + Rust. Starting with this release, it is not possible to use + unstable features on a stable build. + * Arithmetic on basic integer types now + [checks for overflow in debug builds][overflow]. + +* Language + + * [`Send` no longer implies `'static`][send-rfc], which made + possible the [`thread::scoped` API][scoped]. Scoped threads can + borrow data from their parent's stack frame -- safely! + * [UFCS now supports trait-less associated paths][moar-ufcs] like + `MyType::default()`. + * Primitive types [now have inherent methods][prim-inherent], + obviating the need for extension traits like `SliceExt`. + * Methods with `Self: Sized` in their `where` clause are + [considered object-safe][self-sized], allowing many extension + traits like `IteratorExt` to be merged into the traits they + extended. + * You can now [refer to associated types][assoc-where] whose + corresponding trait bounds appear only in a `where` clause. + * The final bits of [OIBIT landed][oibit-final], meaning that + traits like `Send` and `Sync` are now library-defined. + * A [Reflect trait][reflect] was introduced, which means that + downcasting via the `Any` trait is effectively limited to + concrete types. This helps retain the potentially-important + "parametricity" property: generic code cannot behave differently + for different type arguments except in minor ways. + * The `unsafe_destructor` feature is now deprecated in favor of + the [new `dropck`][dropck]. This change is a major reduction in + unsafe code. + * Trait coherence was [revised again][fundamental], this time with + an eye toward API evolution over time. + +* Libraries + + * The new path and IO modules are complete and `#[stable]`. This + was the major library focus for this cycle. + * The path API was [revised][path-normalize] to normalize `.`, + adjusting the tradeoffs in favor of the most common usage. + * A large number of remaining APIs in `std` were also stabilized + during this cycle; about 75% of the non-deprecated API surface + is now stable. + * The new [string pattern API][string-pattern] landed, which makes + the string slice API much more internally consistent and flexible. + * A shiny [framework for Debug implementations][debug-builder] landed. + This makes it possible to opt in to "pretty-printed" debugging output. + * A new set of [generic conversion traits][conversion] replaced + many existing ad hoc traits. + * Generic numeric traits were + [completely removed][num-traits]. This was made possible thanks + to inherent methods for primitive types, and the removal gives + maximal flexibility for designing a numeric hierarchy in the future. + * The `Fn` traits are now related via [inheritance][fn-inherit] + and provide ergonomic [blanket implementations][fn-blanket]. + * The `Index` and `IndexMut` traits were changed to + [take the index by value][index-value], enabling code like + `hash_map["string"]` to work. + * `Copy` now [inherits][copy-clone] from `Clone`, meaning that all + `Copy` data is known to be `Clone` as well. + +* Infrastructure + + * Metadata was tuned, shrinking binaries [by 27%][metadata-shrink]. + * Much headway was made on ecosystem-wide CI, making it possible + to [compare builds for breakage][ci-compare]. + +[send-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0458-send-improvements.md +[scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html +[moar-ufcs]: https://github.com/rust-lang/rust/pull/22172 +[prim-inherent]: https://github.com/rust-lang/rust/pull/23104 +[overflow]: https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md +[metadata-shrink]: https://github.com/rust-lang/rust/pull/22971 +[self-sized]: https://github.com/rust-lang/rust/pull/22301 +[assoc-where]: https://github.com/rust-lang/rust/pull/22512 +[string-pattern]: https://github.com/rust-lang/rust/pull/22466 +[oibit-final]: https://github.com/rust-lang/rust/pull/21689 +[reflect]: https://github.com/rust-lang/rust/pull/23712 +[debug-builder]: https://github.com/rust-lang/rfcs/blob/master/text/0640-debug-improvements.md +[conversion]: https://github.com/rust-lang/rfcs/pull/529 +[num-traits]: https://github.com/rust-lang/rust/pull/23549 +[index-value]: https://github.com/rust-lang/rust/pull/23601 +[dropck]: https://github.com/rust-lang/rfcs/pull/769 +[fundamental]: https://github.com/rust-lang/rfcs/pull/1023 +[ci-compare]: https://gist.github.com/brson/a30a77836fbec057cbee +[fn-inherit]: https://github.com/rust-lang/rust/pull/23282 +[fn-blanket]: https://github.com/rust-lang/rust/pull/23895 +[copy-clone]: https://github.com/rust-lang/rust/pull/23860 +[path-normalize]: https://github.com/rust-lang/rust/pull/23229 + Version 1.0.0-alpha.2 (February 2015) ------------------------------------- diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs index 7fd09f9e1f5b0..f00ff9bcbe5e5 100644 --- a/src/compiletest/compiletest.rs +++ b/src/compiletest/compiletest.rs @@ -31,7 +31,6 @@ extern crate log; use std::env; use std::fs; use std::path::{Path, PathBuf}; -use std::thunk::Thunk; use getopts::{optopt, optflag, reqopt}; use common::Config; use common::{Pretty, DebugInfoGdb, DebugInfoLldb, Codegen}; @@ -351,7 +350,7 @@ pub fn make_test_name(config: &Config, testfile: &Path) -> test::TestName { pub fn make_test_closure(config: &Config, testfile: &Path) -> test::TestFn { let config = (*config).clone(); let testfile = testfile.to_path_buf(); - test::DynTestFn(Thunk::new(move || { + test::DynTestFn(Box::new(move || { runtest::run(config, &testfile) })) } diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index 9612c0e06a34d..f5505b6e83a67 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -311,7 +311,7 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> { parse_name_value_directive(line, "exec-env").map(|nv| { // nv is either FOO or FOO=BAR let mut strs: Vec = nv - .splitn(1, '=') + .splitn(2, '=') .map(|s| s.to_string()) .collect(); diff --git a/src/doc/reference.md b/src/doc/reference.md index b3d5ad3b55d0f..cc90a69fd2ae7 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1648,7 +1648,7 @@ specific type. Implementations are defined with the keyword `impl`. ``` -# #[derive(Copy)] +# #[derive(Copy, Clone)] # struct Point {x: f64, y: f64}; # type Surface = i32; # struct BoundingBox {x: f64, y: f64, width: f64, height: f64}; @@ -1661,6 +1661,10 @@ struct Circle { impl Copy for Circle {} +impl Clone for Circle { + fn clone(&self) -> Circle { *self } +} + impl Shape for Circle { fn draw(&self, s: Surface) { do_draw_circle(s, *self); } fn bounding_box(&self) -> BoundingBox { diff --git a/src/doc/trpl/closures.md b/src/doc/trpl/closures.md index bf4c2d903570b..01b8163ffd372 100644 --- a/src/doc/trpl/closures.md +++ b/src/doc/trpl/closures.md @@ -1,214 +1,478 @@ % Closures -So far, we've made lots of functions in Rust, but we've given them all names. -Rust also allows us to create anonymous functions. Rust's anonymous -functions are called *closures*. By themselves, closures aren't all that -interesting, but when you combine them with functions that take closures as -arguments, really powerful things are possible. +Rust not only has named functions, but anonymous functions as well. Anonymous +functions that have an associated environment are called 'closures', because they +close over an environment. Rust has a really great implementation of them, as +we'll see. -Let's make a closure: +# Syntax -```{rust} -let add_one = |x| { 1 + x }; +Closures look like this: -println!("The sum of 5 plus 1 is {}.", add_one(5)); +```rust +let plus_one = |x: i32| x + 1; + +assert_eq!(2, plus_one(1)); +``` + +We create a binding, `plus_one`, and assign it to a closure. The closure's +arguments go between the pipes (`|`), and the body is an expression, in this +case, `x + 1`. Remember that `{ }` is an expression, so we can have multi-line +closures too: + +```rust +let plus_two = |x| { + let mut result: i32 = x; + + result += 1; + result += 1; + + result +}; + +assert_eq!(4, plus_two(2)); +``` + +You'll notice a few things about closures that are a bit different than regular +functions defined with `fn`. The first of which is that we did not need to +annotate the types of arguments the closure takes or the values it returns. We +can: + +```rust +let plus_one = |x: i32| -> i32 { x + 1 }; + +assert_eq!(2, plus_one(1)); +``` + +But we don't have to. Why is this? Basically, it was chosen for ergonomic reasons. +While specifying the full type for named functions is helpful with things like +documentation and type inference, the types of closures are rarely documented +since they’re anonymous, and they don’t cause the kinds of error-at-a-distance +that inferring named function types can. + +The second is that the syntax is similar, but a bit different. I've added spaces +here to make them look a little closer: + +```rust +fn plus_one_v1 ( x: i32 ) -> i32 { x + 1 } +let plus_one_v2 = |x: i32 | -> i32 { x + 1 }; +let plus_one_v3 = |x: i32 | x + 1 ; ``` -We create a closure using the `|...| { ... }` syntax, and then we create a -binding so we can use it later. Note that we call the function using the -binding name and two parentheses, just like we would for a named function. +Small differences, but they're similar in ways. -Let's compare syntax. The two are pretty close: +# Closures and their environment -```{rust} -let add_one = |x: i32| -> i32 { 1 + x }; -fn add_one (x: i32) -> i32 { 1 + x } +Closures are called such because they 'close over their environment.' It +looks like this: + +```rust +let num = 5; +let plus_num = |x: i32| x + num; + +assert_eq!(10, plus_num(5)); ``` -As you may have noticed, closures infer their argument and return types, so you -don't need to declare one. This is different from named functions, which -default to returning unit (`()`). +This closure, `plus_num`, refers to a `let` binding in its scope: `num`. More +specifically, it borrows the binding. If we do something that would conflict +with that binding, we get an error. Like this one: + +```rust,ignore +let mut num = 5; +let plus_num = |x: i32| x + num; -There's one big difference between a closure and named functions, and it's in -the name: a closure "closes over its environment." What does that mean? It means -this: +let y = &mut num; +``` -```{rust} +Which errors with: + +```text +error: cannot borrow `num` as mutable because it is also borrowed as immutable + let y = &mut num; + ^~~ +note: previous borrow of `num` occurs here due to use in closure; the immutable + borrow prevents subsequent moves or mutable borrows of `num` until the borrow + ends + let plus_num = |x| x + num; + ^~~~~~~~~~~ +note: previous borrow ends here fn main() { - let x: i32 = 5; + let mut num = 5; + let plus_num = |x| x + num; + + let y = &mut num; +} +^ +``` + +A verbose yet helpful error message! As it says, we can't take a mutable borrow +on `num` because the closure is already borrowing it. If we let the closure go +out of scope, we can: + +```rust +let mut num = 5; +{ + let plus_num = |x: i32| x + num; + +} // plus_num goes out of scope, borrow of num ends - let printer = || { println!("x is: {}", x); }; +let y = &mut num; +``` + +If your closure requires it, however, Rust will take ownership and move +the environment instead: + +```rust,ignore +let nums = vec![1, 2, 3]; + +let takes_nums = || nums; + +println!("{:?}", nums); +``` + +This gives us: + +```text +note: `nums` moved into closure environment here because it has type + `[closure(()) -> collections::vec::Vec]`, which is non-copyable +let takes_nums = || nums; + ^~~~~~~ +``` + +`Vec` has ownership over its contents, and therefore, when we refer to it +in our closure, we have to take ownership of `nums`. It's the same as if we'd +passed `nums` to a function that took ownership of it. + +## `move` closures + +We can force our closure to take ownership of its environment with the `move` +keyword: - printer(); // prints "x is: 5" +```rust +let num = 5; + +let owns_num = move |x: i32| x + num; +``` + +Now, even though the keyword is `move`, the variables follow normal move semantics. +In this case, `5` implements `Copy`, and so `owns_num` takes ownership of a copy +of `num`. So what's the difference? + +```rust +let mut num = 5; + +{ + let mut add_num = |x: i32| num += x; + + add_num(5); } + +assert_eq!(10, num); ``` -The `||` syntax means this is an anonymous closure that takes no arguments. -Without it, we'd just have a block of code in `{}`s. +So in this case, our closure took a mutable reference to `num`, and then when +we called `add_num`, it mutated the underlying value, as we'd expect. We also +needed to declare `add_num` as `mut` too, because we’re mutating its +environment. -In other words, a closure has access to variables in the scope where it's -defined. The closure borrows any variables it uses, so this will error: +We also had to declare `add_num` as mut, since we will be modifying its +environment. -```{rust,ignore} -fn main() { - let mut x: i32 = 5; +If we change to a `move` closure, it's different: + +```rust +let mut num = 5; - let printer = || { println!("x is: {}", x); }; +{ + let mut add_num = move |x: i32| num += x; - x = 6; // error: cannot assign to `x` because it is borrowed + add_num(5); } + +assert_eq!(5, num); ``` -## Moving closures +We only get `5`. Rather than taking a mutable borrow out on our `num`, we took +ownership of a copy. + +Another way to think about `move` closures: they give a closure its own stack +frame. Without `move`, a closure may be tied to the stack frame that created +it, while a `move` closure is self-contained. This means that you cannot +generally return a non-`move` closure from a function, for example. + +But before we talk about taking and returning closures, we should talk some more +about the way that closures are implemented. As a systems language, Rust gives +you tons of control over what your code does, and closures are no different. -Rust has a second type of closure, called a *moving closure*. Moving -closures are indicated using the `move` keyword (e.g., `move || x * -x`). The difference between a moving closure and an ordinary closure -is that a moving closure always takes ownership of all variables that -it uses. Ordinary closures, in contrast, just create a reference into -the enclosing stack frame. Moving closures are most useful with Rust's -concurrency features, and so we'll just leave it at this for -now. We'll talk about them more in the "Concurrency" chapter of the book. +# Closure implementation -## Accepting closures as arguments +Rust's implementation of closures is a bit different than other languages. They +are effectively syntax sugar for traits. You'll want to make sure to have read +the [traits chapter][traits] before this one, as well as the chapter on [static +and dynamic dispatch][dispatch], which talks about trait objects. -Closures are most useful as an argument to another function. Here's an example: +[traits]: traits.html +[dispatch]: static-and-dynamic-dispatch.html -```{rust} -fn twice i32>(x: i32, f: F) -> i32 { - f(x) + f(x) +Got all that? Good. + +The key to understanding how closures work under the hood is something a bit +strange: Using `()` to call a function, like `foo()`, is an overloadable +operator. From this, everything else clicks into place. In Rust, we use the +trait system to overload operators. Calling functions is no different. We have +three separate traits to overload with: + +```rust +# mod foo { +pub trait Fn : FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; } -fn main() { - let square = |x: i32| { x * x }; +pub trait FnMut : FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +pub trait FnOnce { + type Output; - twice(5, square); // evaluates to 50 + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } +# } ``` -Let's break the example down, starting with `main`: +You'll notice a few differences between these traits, but a big one is `self`: +`Fn` takes `&self`, `FnMut` takes `&mut self`, and `FnOnce` takes `self`. This +covers all three kinds of `self` via the usual method call syntax. But we've +split them up into three traits, rather than having a single one. This gives us +a large amount of control over what kind of closures we can take. -```{rust} -let square = |x: i32| { x * x }; -``` +The `|| {}` syntax for closures is sugar for these three traits. Rust will +generate a struct for the environment, `impl` the appropriate trait, and then +use it. + +# Taking closures as arguments + +Now that we know that closures are traits, we already know how to accept and +return closures: just like any other trait! + +This also means that we can choose static vs dynamic dispatch as well. First, +let's write a function which takes something callable, calls it, and returns +the result: + +```rust +fn call_with_one(some_closure: F) -> i32 + where F : Fn(i32) -> i32 { + + some_closure(1) +} -We've seen this before. We make a closure that takes an integer, and returns -its square. +let answer = call_with_one(|x| x + 2); -```{rust} -# fn twice i32>(x: i32, f: F) -> i32 { f(x) + f(x) } -# let square = |x: i32| { x * x }; -twice(5, square); // evaluates to 50 +assert_eq!(3, answer); ``` -This line is more interesting. Here, we call our function, `twice`, and we pass -it two arguments: an integer, `5`, and our closure, `square`. This is just like -passing any other two variable bindings to a function, but if you've never -worked with closures before, it can seem a little complex. Just think: "I'm -passing two variables: one is an i32, and one is a function." +We pass our closure, `|x| x + 2`, to `call_with_one`. It just does what it +suggests: it calls the closure, giving it `1` as an argument. -Next, let's look at how `twice` is defined: +Let's examine the signature of `call_with_one` in more depth: -```{rust,ignore} -fn twice i32>(x: i32, f: F) -> i32 { +```rust +fn call_with_one(some_closure: F) -> i32 +# where F : Fn(i32) -> i32 { +# some_closure(1) } ``` -`twice` takes two arguments, `x` and `f`. That's why we called it with two -arguments. `x` is an `i32`, we've done that a ton of times. `f` is a function, -though, and that function takes an `i32` and returns an `i32`. This is -what the requirement `Fn(i32) -> i32` for the type parameter `F` says. -Now `F` represents *any* function that takes an `i32` and returns an `i32`. +We take one parameter, and it has the type `F`. We also return a `i32`. This part +isn't interesting. The next part is: -This is the most complicated function signature we've seen yet! Give it a read -a few times until you can see how it works. It takes a teeny bit of practice, and -then it's easy. The good news is that this kind of passing a closure around -can be very efficient. With all the type information available at compile-time -the compiler can do wonders. +```rust +# fn call_with_one(some_closure: F) -> i32 + where F : Fn(i32) -> i32 { +# some_closure(1) } +``` + +Because `Fn` is a trait, we can bound our generic with it. In this case, our closure +takes a `i32` as an argument and returns an `i32`, and so the generic bound we use +is `Fn(i32) -> i32`. -Finally, `twice` returns an `i32` as well. +There's one other key point here: because we're bounding a generic with a +trait, this will get monomorphized, and therefore, we'll be doing static +dispatch into the closure. That's pretty neat. In many langauges, closures are +inherently heap allocated, and will always involve dynamic dispatch. In Rust, +we can stack allocate our closure environment, and statically dispatch the +call. This happens quite often with iterators and their adapters, which often +take closures as arguments. -Okay, let's look at the body of `twice`: +Of course, if we want dynamic dispatch, we can get that too. A trait object +handles this case, as usual: -```{rust} -fn twice i32>(x: i32, f: F) -> i32 { - f(x) + f(x) +```rust +fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 { + some_closure(1) } + +let answer = call_with_one(&|x| x + 2); + +assert_eq!(3, answer); ``` -Since our closure is named `f`, we can call it just like we called our closures -before, and we pass in our `x` argument to each one, hence the name `twice`. +Now we take a trait object, a `&Fn`. And we have to make a reference +to our closure when we pass it to `call_with_one`, so we use `&||`. -If you do the math, `(5 * 5) + (5 * 5) == 50`, so that's the output we get. +# Returning closures -Play around with this concept until you're comfortable with it. Rust's standard -library uses lots of closures where appropriate, so you'll be using -this technique a lot. +It’s very common for functional-style code to return closures in various +situations. If you try to return a closure, you may run into an error. At +first, it may seem strange, but we'll figure it out. Here's how you'd probably +try to return a closure from a function: -If we didn't want to give `square` a name, we could just define it inline. -This example is the same as the previous one: +```rust,ignore +fn factory() -> (Fn(i32) -> Vec) { + let vec = vec![1, 2, 3]; -```{rust} -fn twice i32>(x: i32, f: F) -> i32 { - f(x) + f(x) + |n| vec.push(n) } -fn main() { - twice(5, |x: i32| { x * x }); // evaluates to 50 -} +let f = factory(); + +let answer = f(4); +assert_eq!(vec![1, 2, 3, 4], answer); ``` -A named function's name can be used wherever you'd use a closure. Another -way of writing the previous example: +This gives us these long, related errors: + +```text +error: the trait `core::marker::Sized` is not implemented for the type +`core::ops::Fn(i32) -> collections::vec::Vec` [E0277] +f = factory(); +^ +note: `core::ops::Fn(i32) -> collections::vec::Vec` does not have a +constant size known at compile-time +f = factory(); +^ +error: the trait `core::marker::Sized` is not implemented for the type +`core::ops::Fn(i32) -> collections::vec::Vec` [E0277] +factory() -> (Fn(i32) -> Vec) { + ^~~~~~~~~~~~~~~~~~~~~ +note: `core::ops::Fn(i32) -> collections::vec::Vec` does not have a constant size known at compile-time +fa ctory() -> (Fn(i32) -> Vec) { + ^~~~~~~~~~~~~~~~~~~~~ -```{rust} -fn twice i32>(x: i32, f: F) -> i32 { - f(x) + f(x) -} +``` -fn square(x: i32) -> i32 { x * x } +In order to return something from a function, Rust needs to know what +size the return type is. But since `Fn` is a trait, it could be various +things of various sizes: many different types can implement `Fn`. An easy +way to give something a size is to take a reference to it, as references +have a known size. So we'd write this: -fn main() { - twice(5, square); // evaluates to 50 +```rust,ignore +fn factory() -> &(Fn(i32) -> Vec) { + let vec = vec![1, 2, 3]; + + |n| vec.push(n) } + +let f = factory(); + +let answer = f(4); +assert_eq!(vec![1, 2, 3, 4], answer); +``` + +But we get another error: + +```text +error: missing lifetime specifier [E0106] +fn factory() -> &(Fn(i32) -> i32) { + ^~~~~~~~~~~~~~~~~ ``` -Doing this is not particularly common, but it's useful every once in a while. +Right. Because we have a reference, we need to give it a lifetime. But +our `factory()` function takes no arguments, so elision doesn't kick in +here. What lifetime can we choose? `'static`: -Before we move on, let us look at a function that accepts two closures. +```rust,ignore +fn factory() -> &'static (Fn(i32) -> i32) { + let num = 5; -```{rust} -fn compose(x: i32, f: F, g: G) -> i32 - where F: Fn(i32) -> i32, G: Fn(i32) -> i32 { - g(f(x)) + |x| x + num } -fn main() { - compose(5, - |n: i32| { n + 42 }, - |n: i32| { n * 2 }); // evaluates to 94 +let f = factory(); + +let answer = f(1); +assert_eq!(6, answer); +``` + +But we get another error: + +```text +error: mismatched types: + expected `&'static core::ops::Fn(i32) -> i32`, + found `[closure :7:9: 7:20]` +(expected &-ptr, + found closure) [E0308] + |x| x + num + ^~~~~~~~~~~ + +``` + +This error is letting us know that we don't have a `&'static Fn(i32) -> i32`, +we have a `[closure :7:9: 7:20]`. Wait, what? + +Because each closure generates its own environment `struct` and implementation +of `Fn` and friends, these types are anonymous. They exist just solely for +this closure. So Rust shows them as `closure `, rather than some +autogenerated name. + +But why doesn't our closure implement `&'static Fn`? Well, as we discussed before, +closures borrow their environment. And in this case, our environment is based +on a stack-allocated `5`, the `num` variable binding. So the borrow has a lifetime +of the stack frame. So if we returned this closure, the function call would be +over, the stack frame would go away, and our closure is capturing an environment +of garbage memory! + +So what to do? This _almost_ works: + +```rust,ignore +fn factory() -> Box i32> { + let num = 5; + + Box::new(|x| x + num) } +# fn main() { +let f = factory(); + +let answer = f(1); +assert_eq!(6, answer); +# } ``` -You might ask yourself: why do we need to introduce two type -parameters `F` and `G` here? Evidently, both `f` and `g` have the -same signature: `Fn(i32) -> i32`. +We use a trait object, by `Box`ing up the `Fn`. There's just one last problem: -That is because in Rust each closure has its own unique type. -So, not only do closures with different signatures have different types, -but different closures with the *same* signature have *different* -types, as well! +```text +error: `num` does not live long enough +Box::new(|x| x + num) + ^~~~~~~~~~~ +``` + +We still have a reference to the parent stack frame. With one last fix, we can +make this work: -You can think of it this way: the behavior of a closure is part of its -type. Therefore, using a single type parameter for both closures -will accept the first of them, rejecting the second. The distinct -type of the second closure does not allow it to be represented by the -same type parameter as that of the first. We acknowledge this, and -use two different type parameters `F` and `G`. +```rust +fn factory() -> Box i32> { + let num = 5; -This also introduces the `where` clause, which lets us describe type -parameters in a more flexible manner. + Box::new(move |x| x + num) +} +# fn main() { +let f = factory(); + +let answer = f(1); +assert_eq!(6, answer); +# } +``` -That's all you need to get the hang of closures! Closures are a little bit -strange at first, but once you're used to them, you'll miss them -in other languages. Passing functions to other functions is -incredibly powerful, as you will see in the following chapter about iterators. +By making the inner closure a `move Fn`, we create a new stack frame for our +closure. By `Box`ing it up, we've given it a known size, and allowing it to +escape our stack frame. diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index cf60bd88c542b..b9e7bd78c5b2f 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -200,15 +200,15 @@ Because these kinds of situations are relatively rare, use panics sparingly. # Upgrading failures to panics In certain circumstances, even though a function may fail, we may want to treat -it as a panic instead. For example, `io::stdin().read_line()` returns an -`IoResult`, a form of `Result`, when there is an error reading the -line. This allows us to handle and possibly recover from this sort of error. +it as a panic instead. For example, `io::stdin().read_line(&mut buffer)` returns +an `Result`, when there is an error reading the line. This allows us to +handle and possibly recover from error. If we don't want to handle this error, and would rather just abort the program, we can use the `unwrap()` method: ```{rust,ignore} -io::stdin().read_line().unwrap(); +io::stdin().read_line(&mut buffer).unwrap(); ``` `unwrap()` will `panic!` if the `Option` is `None`. This basically says "Give @@ -219,12 +219,13 @@ shorter. Sometimes, just crashing is appropriate. There's another way of doing this that's a bit nicer than `unwrap()`: ```{rust,ignore} -let input = io::stdin().read_line() +let mut buffer = String::new(); +let input = io::stdin().read_line(&mut buffer) .ok() .expect("Failed to read line"); ``` -`ok()` converts the `IoResult` into an `Option`, and `expect()` does the same +`ok()` converts the `Result` 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. diff --git a/src/etc/rustup.sh b/src/etc/rustup.sh index 47e64547eed39..918c0c66f76df 100755 --- a/src/etc/rustup.sh +++ b/src/etc/rustup.sh @@ -288,6 +288,7 @@ VAL_OPTIONS="" flag uninstall "only uninstall from the installation prefix" valopt prefix "" "set installation prefix" valopt date "" "use the YYYY-MM-DD nightly instead of the current nightly" +valopt channel "beta" "use the selected release channel [beta]" flag save "save the downloaded nightlies to ~/.rustup" if [ $HELP -eq 1 ] @@ -307,7 +308,7 @@ CFG_CPUTYPE=$(uname -m) if [ $CFG_OSTYPE = Darwin -a $CFG_CPUTYPE = i386 ] then - # Darwin's `uname -s` lies and always returns i386. We have to use sysctl + # Darwin's `uname -m` lies and always returns i386. We have to use sysctl # instead. if sysctl hw.optional.x86_64 | grep -q ': 1' then @@ -449,18 +450,28 @@ then fi RUST_URL="https://static.rust-lang.org/dist" -RUST_PACKAGE_NAME=rust-nightly +case "$CFG_CHANNEL" in + nightly) + # add a date suffix if we want a particular nightly. + if [ -n "${CFG_DATE}" ]; + then + RUST_URL="${RUST_URL}/${CFG_DATE}" + fi + + RUST_PACKAGE_NAME=rust-nightly + ;; + beta) + RUST_PACKAGE_NAME=rust-1.0.0-beta + ;; + *) + err "Currently 'beta' and 'nightly' are the only supported channels" +esac + RUST_PACKAGE_NAME_AND_TRIPLE="${RUST_PACKAGE_NAME}-${HOST_TRIPLE}" RUST_TARBALL_NAME="${RUST_PACKAGE_NAME_AND_TRIPLE}.tar.gz" RUST_LOCAL_INSTALL_DIR="${CFG_TMP_DIR}/${RUST_PACKAGE_NAME_AND_TRIPLE}" RUST_LOCAL_INSTALL_SCRIPT="${RUST_LOCAL_INSTALL_DIR}/install.sh" -# add a date suffix if we want a particular nighly. -if [ -n "${CFG_DATE}" ]; -then - RUST_URL="${RUST_URL}/${CFG_DATE}" -fi - download_hash() { msg "Downloading ${remote_sha256}" remote_sha256=`"${CFG_CURL}" -f "${remote_sha256}"` diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs index 855c86f08e745..8b884c56505b2 100644 --- a/src/liballoc/arc.rs +++ b/src/liballoc/arc.rs @@ -242,6 +242,41 @@ pub fn weak_count(this: &Arc) -> usize { this.inner().weak.load(SeqCst) - #[unstable(feature = "alloc")] pub fn strong_count(this: &Arc) -> usize { this.inner().strong.load(SeqCst) } + +/// Try accessing a mutable reference to the contents behind an unique `Arc`. +/// +/// The access is granted only if this is the only reference to the object. +/// Otherwise, `None` is returned. +/// +/// # Examples +/// +/// ``` +/// # #![feature(alloc)] +/// extern crate alloc; +/// # fn main() { +/// use alloc::arc; +/// +/// let mut four = arc::Arc::new(4); +/// +/// arc::unique(&mut four).map(|num| *num = 5); +/// # } +/// ``` +#[inline] +#[unstable(feature = "alloc")] +pub fn unique(this: &mut Arc) -> Option<&mut T> { + if strong_count(this) == 1 && weak_count(this) == 0 { + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + let inner = unsafe { &mut **this._ptr }; + Some(&mut inner.data) + }else { + None + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Arc { /// Makes a clone of the `Arc`. @@ -286,7 +321,7 @@ impl Deref for Arc { } } -impl Arc { +impl Arc { /// Make a mutable reference from the given `Arc`. /// /// This is also referred to as a copy-on-write operation because the inner @@ -312,11 +347,8 @@ impl Arc { self.inner().weak.load(SeqCst) != 1 { *self = Arc::new((**self).clone()) } - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the Arc itself to be `mut`, so we're returning the only possible - // reference to the inner data. + // As with `unique()`, the unsafety is ok because our reference was + // either unique to begin with, or became one upon cloning the contents. let inner = unsafe { &mut **self._ptr }; &mut inner.data } @@ -433,7 +465,7 @@ impl Weak { #[unstable(feature = "alloc", reason = "Weak pointers may not belong in this module.")] -impl Clone for Weak { +impl Clone for Weak { /// Makes a clone of the `Weak`. /// /// This increases the weak reference count. @@ -659,7 +691,7 @@ mod tests { use std::sync::atomic::Ordering::{Acquire, SeqCst}; use std::thread; use std::vec::Vec; - use super::{Arc, Weak, weak_count, strong_count}; + use super::{Arc, Weak, weak_count, strong_count, unique}; use std::sync::Mutex; struct Canary(*mut atomic::AtomicUsize); @@ -695,6 +727,21 @@ mod tests { assert_eq!((*arc_v)[4], 5); } + #[test] + fn test_arc_unique() { + let mut x = Arc::new(10); + assert!(unique(&mut x).is_some()); + { + let y = x.clone(); + assert!(unique(&mut x).is_none()); + } + { + let z = x.downgrade(); + assert!(unique(&mut x).is_none()); + } + assert!(unique(&mut x).is_some()); + } + #[test] fn test_cowarc_clone_make_unique() { let mut cow0 = Arc::new(75); diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 550b25ac3a7cf..2801cf38cb755 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -51,15 +51,12 @@ use core::prelude::*; use core::any::Any; use core::cmp::Ordering; use core::default::Default; -use core::error::Error; use core::fmt; use core::hash::{self, Hash}; use core::mem; use core::ops::{Deref, DerefMut}; -use core::ptr::{self, Unique}; -use core::raw::{TraitObject, Slice}; - -use heap; +use core::ptr::{Unique}; +use core::raw::{TraitObject}; /// A value that represents the heap. This is the default place that the `box` /// keyword allocates into when no place is supplied. @@ -86,6 +83,7 @@ pub static HEAP: () = (); /// See the [module-level documentation](../../std/boxed/index.html) for more. #[lang = "owned_box"] #[stable(feature = "rust1", since = "1.0.0")] +#[fundamental] pub struct Box(Unique); impl Box { @@ -277,13 +275,6 @@ impl fmt::Debug for Box { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Box { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("Box") - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Deref for Box { type Target = T; @@ -309,49 +300,74 @@ impl DoubleEndedIterator for Box { #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Box {} -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) + +/// `FnBox` is a version of the `FnOnce` intended for use with boxed +/// closure objects. The idea is that where one would normally store a +/// `Box` in a data structure, you should use +/// `Box`. The two traits behave essentially the same, except +/// that a `FnBox` closure can only be called if it is boxed. (Note +/// that `FnBox` may be deprecated in the future if `Box` +/// closures become directly usable.) +/// +/// ### Example +/// +/// Here is a snippet of code which creates a hashmap full of boxed +/// once closures and then removes them one by one, calling each +/// closure as it is removed. Note that the type of the closures +/// stored in the map is `Box i32>` and not `Box i32>`. +/// +/// ``` +/// #![feature(core)] +/// +/// use std::boxed::FnBox; +/// use std::collections::HashMap; +/// +/// fn make_map() -> HashMap i32>> { +/// let mut map: HashMap i32>> = HashMap::new(); +/// map.insert(1, Box::new(|| 22)); +/// map.insert(2, Box::new(|| 44)); +/// map +/// } +/// +/// fn main() { +/// let mut map = make_map(); +/// for i in &[1, 2] { +/// let f = map.remove(&i).unwrap(); +/// assert_eq!(f(), i * 22); +/// } +/// } +/// ``` +#[rustc_paren_sugar] +#[unstable(feature = "core", reason = "Newly introduced")] +pub trait FnBox { + type Output; + + fn call_box(self: Box, args: A) -> Self::Output; +} + +impl FnBox for F + where F: FnOnce +{ + type Output = F::Output; + + fn call_box(self: Box, args: A) -> F::Output { + self.call_once(args) } } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, E: Error + Send + 'a> From for Box { - fn from(err: E) -> Box { - Box::new(err) +impl<'a,A,R> FnOnce for Box+'a> { + type Output = R; + + extern "rust-call" fn call_once(self, args: A) -> R { + self.call_box(args) } } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> From<&'b str> for Box { - fn from(err: &'b str) -> Box { - #[derive(Debug)] - struct StringError(Box); - impl Error for StringError { - fn description(&self) -> &str { &self.0 } - } - impl fmt::Display for StringError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.fmt(f) - } - } +impl<'a,A,R> FnOnce for Box+Send+'a> { + type Output = R; - // Unfortunately `String` is located in libcollections, so we construct - // a `Box` manually here. - unsafe { - let alloc = if err.len() == 0 { - 0 as *mut u8 - } else { - let ptr = heap::allocate(err.len(), 1); - if ptr.is_null() { ::oom(); } - ptr as *mut u8 - }; - ptr::copy(err.as_bytes().as_ptr(), alloc, err.len()); - Box::new(StringError(mem::transmute(Slice { - data: alloc, - len: err.len(), - }))) - } + extern "rust-call" fn call_once(self, args: A) -> R { + self.call_box(args) } } diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 682d5f407c4ea..fc44ac4eac628 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -55,17 +55,17 @@ fn test_show() { let b = Box::new(Test) as Box; let a_str = format!("{:?}", a); let b_str = format!("{:?}", b); - assert_eq!(a_str, "Box"); - assert_eq!(b_str, "Box"); + assert_eq!(a_str, "Any"); + assert_eq!(b_str, "Any"); static EIGHT: usize = 8; static TEST: Test = Test; let a = &EIGHT as &Any; let b = &TEST as &Any; let s = format!("{:?}", a); - assert_eq!(s, "&Any"); + assert_eq!(s, "Any"); let s = format!("{:?}", b); - assert_eq!(s, "&Any"); + assert_eq!(s, "Any"); } #[test] diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index b92dfa9117e6b..a8be63d637359 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -71,6 +71,8 @@ #![feature(no_std)] #![no_std] #![feature(allocator)] +#![feature(custom_attribute)] +#![feature(fundamental)] #![feature(lang_items, unsafe_destructor)] #![feature(box_syntax)] #![feature(optin_builtin_traits)] diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs index e4bc6a393c491..3804874a650f6 100644 --- a/src/libcollections/binary_heap.rs +++ b/src/libcollections/binary_heap.rs @@ -30,7 +30,7 @@ //! use std::collections::BinaryHeap; //! use std::usize; //! -//! #[derive(Copy, Eq, PartialEq)] +//! #[derive(Copy, Clone, Eq, PartialEq)] //! struct State { //! cost: usize, //! position: usize, diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs index 847ee7c19ce94..26c57256049cb 100644 --- a/src/libcollections/btree/node.rs +++ b/src/libcollections/btree/node.rs @@ -526,7 +526,7 @@ impl Clone for Node { /// println!("Uninitialized memory: {:?}", handle.into_kv()); /// } /// ``` -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Handle { node: NodeRef, index: usize, diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs index 474b4de8123e1..0b206d381ddac 100644 --- a/src/libcollections/enum_set.rs +++ b/src/libcollections/enum_set.rs @@ -21,7 +21,7 @@ use core::ops::{Sub, BitOr, BitAnd, BitXor}; // FIXME(contentions): implement union family of methods? (general design may be wrong here) -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)] /// A specialized set implementation to use enum types. /// /// It is a logic error for an item to be modified in such a way that the transformation of the @@ -37,6 +37,10 @@ pub struct EnumSet { impl Copy for EnumSet {} +impl Clone for EnumSet { + fn clone(&self) -> EnumSet { *self } +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Debug for EnumSet { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index 29301bfd6fe7e..ff923fb19068f 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -328,9 +328,12 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to splitting at most `n` times. The matched element is + /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// /// # Examples /// /// Print the slice split once by numbers divisible by 3 (i.e. `[10, 40]`, @@ -338,7 +341,7 @@ impl [T] { /// /// ``` /// let v = [10, 40, 30, 20, 60, 50]; - /// for group in v.splitn(1, |num| *num % 3 == 0) { + /// for group in v.splitn(2, |num| *num % 3 == 0) { /// println!("{:?}", group); /// } /// ``` @@ -349,10 +352,13 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to splitting at most `n` times. This starts at the end of + /// `pred` limited to returning at most `n` items. This starts at the end of /// the slice and works backwards. The matched element is not contained in /// the subslices. /// + /// The last element returned, if any, will contain the remainder of the + /// slice. + /// /// # Examples /// /// Print the slice split once, starting from the end, by numbers divisible @@ -360,7 +366,7 @@ impl [T] { /// /// ``` /// let v = [10, 40, 30, 20, 60, 50]; - /// for group in v.rsplitn(1, |num| *num % 3 == 0) { + /// for group in v.rsplitn(2, |num| *num % 3 == 0) { /// println!("{:?}", group); /// } /// ``` @@ -626,8 +632,11 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred`, limited to splitting at most `n` times. The matched element is + /// `pred`, limited to returning at most `n` items. The matched element is /// not contained in the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut @@ -636,9 +645,12 @@ impl [T] { } /// Returns an iterator over subslices separated by elements that match - /// `pred` limited to splitting at most `n` times. This starts at the end of + /// `pred` limited to returning at most `n` items. This starts at the end of /// the slice and works backwards. The matched element is not contained in /// the subslices. + /// + /// The last element returned, if any, will contain the remainder of the + /// slice. #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index f8f2909291f3e..c22b6fb9286d1 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -610,24 +610,27 @@ impl str { core_str::StrExt::split(&self[..], pat) } - /// An iterator over substrings of `self`, separated by characters matched by a pattern, - /// restricted to splitting at most `count` times. + /// An iterator over substrings of `self`, separated by characters matched + /// by a pattern, returning most `count` items. /// /// The pattern can be a simple `&str`, or a closure that determines /// the split. /// + /// The last element returned, if any, will contain the remainder of the + /// string. + /// /// # Examples /// /// Simple `&str` patterns: /// /// ``` /// let v: Vec<&str> = "Mary had a little lambda".splitn(2, ' ').collect(); - /// assert_eq!(v, ["Mary", "had", "a little lambda"]); + /// assert_eq!(v, ["Mary", "had a little lambda"]); /// /// let v: Vec<&str> = "lionXXtigerXleopard".splitn(2, 'X').collect(); - /// assert_eq!(v, ["lion", "", "tigerXleopard"]); + /// assert_eq!(v, ["lion", "XtigerXleopard"]); /// - /// let v: Vec<&str> = "abcXdef".splitn(0, 'X').collect(); + /// let v: Vec<&str> = "abcXdef".splitn(1, 'X').collect(); /// assert_eq!(v, ["abcXdef"]); /// /// let v: Vec<&str> = "".splitn(1, 'X').collect(); @@ -637,7 +640,7 @@ impl str { /// More complex patterns with a lambda: /// /// ``` - /// let v: Vec<&str> = "abc1def2ghi".splitn(1, |c: char| c.is_numeric()).collect(); + /// let v: Vec<&str> = "abc1def2ghi".splitn(2, |c: char| c.is_numeric()).collect(); /// assert_eq!(v, ["abc", "def2ghi"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -705,25 +708,28 @@ impl str { } /// An iterator over substrings of `self`, separated by a pattern, - /// starting from the end of the string, restricted to splitting - /// at most `count` times. + /// starting from the end of the string, restricted to returning + /// at most `count` items. + /// + /// The last element returned, if any, will contain the remainder of the + /// string. /// /// # Examples /// /// Simple patterns: /// /// ``` - /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(2, ' ').collect(); + /// let v: Vec<&str> = "Mary had a little lamb".rsplitn(3, ' ').collect(); /// assert_eq!(v, ["lamb", "little", "Mary had a"]); /// - /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(1, "::").collect(); + /// let v: Vec<&str> = "lion::tiger::leopard".rsplitn(2, "::").collect(); /// assert_eq!(v, ["leopard", "lion::tiger"]); /// ``` /// /// More complex patterns with a lambda: /// /// ``` - /// let v: Vec<&str> = "abc1def2ghi".rsplitn(1, |c: char| c.is_numeric()).collect(); + /// let v: Vec<&str> = "abc1def2ghi".rsplitn(2, |c: char| c.is_numeric()).collect(); /// assert_eq!(v, ["ghi", "abc1def"]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index d8d7ad9887a8c..7a7725320914f 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -17,7 +17,6 @@ use core::prelude::*; use core::default::Default; -use core::error::Error; use core::fmt; use core::hash; use core::iter::{IntoIterator, FromIterator}; @@ -723,11 +722,6 @@ impl fmt::Display for FromUtf8Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf8Error { - fn description(&self) -> &str { "invalid utf-8" } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for FromUtf16Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -735,11 +729,6 @@ impl fmt::Display for FromUtf16Error { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for FromUtf16Error { - fn description(&self) -> &str { "invalid utf-16" } -} - #[stable(feature = "rust1", since = "1.0.0")] impl FromIterator for String { fn from_iter>(iter: I) -> String { diff --git a/src/libcollectionstest/enum_set.rs b/src/libcollectionstest/enum_set.rs index a748541fca5ce..0a1eb0bcfa887 100644 --- a/src/libcollectionstest/enum_set.rs +++ b/src/libcollectionstest/enum_set.rs @@ -14,7 +14,7 @@ use collections::enum_set::{CLike, EnumSet}; use self::Foo::*; -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] #[repr(usize)] enum Foo { A, B, C @@ -218,7 +218,7 @@ fn test_operators() { #[should_panic] fn test_overflow() { #[allow(dead_code)] - #[derive(Copy)] + #[derive(Copy, Clone)] #[repr(usize)] enum Bar { V00, V01, V02, V03, V04, V05, V06, V07, V08, V09, diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index dab5da10db421..5b0aceb76d19c 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -867,18 +867,18 @@ fn test_splitnator() { let xs = &[1,2,3,4,5]; let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.splitn(0, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[1], &[3,4,5]]; - assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn(2, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[], &[], &[], &[4,5]]; - assert_eq!(xs.splitn(3, |_| true).collect::>(), + assert_eq!(xs.splitn(4, |_| true).collect::>(), splits); let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.splitn(1, |x| *x == 5).collect::>(), splits); + assert_eq!(xs.splitn(2, |x| *x == 5).collect::>(), splits); } #[test] @@ -886,18 +886,18 @@ fn test_splitnator_mut() { let xs = &mut [1,2,3,4,5]; let splits: &[&mut[_]] = &[&mut [1,2,3,4,5]]; - assert_eq!(xs.splitn_mut(0, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&mut[_]] = &[&mut [1], &mut [3,4,5]]; - assert_eq!(xs.splitn_mut(1, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.splitn_mut(2, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&mut[_]] = &[&mut [], &mut [], &mut [], &mut [4,5]]; - assert_eq!(xs.splitn_mut(3, |_| true).collect::>(), + assert_eq!(xs.splitn_mut(4, |_| true).collect::>(), splits); let xs: &mut [i32] = &mut []; let splits: &[&mut[i32]] = &[&mut []]; - assert_eq!(xs.splitn_mut(1, |x| *x == 5).collect::>(), + assert_eq!(xs.splitn_mut(2, |x| *x == 5).collect::>(), splits); } @@ -928,18 +928,19 @@ fn test_rsplitnator() { let xs = &[1,2,3,4,5]; let splits: &[&[_]] = &[&[1,2,3,4,5]]; - assert_eq!(xs.rsplitn(0, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[5], &[1,2,3]]; - assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::>(), + assert_eq!(xs.rsplitn(2, |x| *x % 2 == 0).collect::>(), splits); let splits: &[&[_]] = &[&[], &[], &[], &[1,2]]; - assert_eq!(xs.rsplitn(3, |_| true).collect::>(), + assert_eq!(xs.rsplitn(4, |_| true).collect::>(), splits); let xs: &[i32] = &[]; let splits: &[&[i32]] = &[&[]]; - assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::>(), splits); + assert_eq!(xs.rsplitn(2, |x| *x == 5).collect::>(), splits); + assert!(xs.rsplitn(0, |x| *x % 2 == 0).next().is_none()); } #[test] diff --git a/src/libcollectionstest/str.rs b/src/libcollectionstest/str.rs index ed9ee0206b74f..495a961fa360e 100644 --- a/src/libcollectionstest/str.rs +++ b/src/libcollectionstest/str.rs @@ -885,17 +885,17 @@ fn test_char_indices_revator() { fn test_splitn_char_iterator() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - let split: Vec<&str> = data.splitn(3, ' ').collect(); + let split: Vec<&str> = data.splitn(4, ' ').collect(); 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(); + let split: Vec<&str> = data.splitn(4, |c: char| c == ' ').collect(); assert_eq!(split, ["\nMäry", "häd", "ä", "little lämb\nLittle lämb\n"]); // Unicode - let split: Vec<&str> = data.splitn(3, 'ä').collect(); + let split: Vec<&str> = data.splitn(4, 'ä').collect(); 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(); + let split: Vec<&str> = data.splitn(4, |c: char| c == 'ä').collect(); assert_eq!(split, ["\nM", "ry h", "d ", " little lämb\nLittle lämb\n"]); } @@ -928,13 +928,13 @@ fn test_rsplit() { fn test_rsplitn() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - let split: Vec<&str> = data.rsplitn(1, ' ').collect(); + let split: Vec<&str> = data.rsplitn(2, ' ').collect(); assert_eq!(split, ["lämb\n", "\nMäry häd ä little lämb\nLittle"]); - let split: Vec<&str> = data.rsplitn(1, "lämb").collect(); + let split: Vec<&str> = data.rsplitn(2, "lämb").collect(); assert_eq!(split, ["\n", "\nMäry häd ä little lämb\nLittle "]); - let split: Vec<&str> = data.rsplitn(1, |c: char| c == 'ä').collect(); + let split: Vec<&str> = data.rsplitn(2, |c: char| c == 'ä').collect(); assert_eq!(split, ["mb\n", "\nMäry häd ä little lämb\nLittle l"]); } diff --git a/src/libcore/any.rs b/src/libcore/any.rs index 0ffc4a229b5ae..320fdd50b3510 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -71,6 +71,7 @@ #![stable(feature = "rust1", since = "1.0.0")] +use fmt; use marker::Send; use mem::transmute; use option::Option::{self, Some, None}; @@ -105,6 +106,13 @@ impl Any for T // Extension methods for Any trait objects. /////////////////////////////////////////////////////////////////////////////// +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Any { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Any") + } +} + impl Any { /// Returns true if the boxed type is the same as `T` #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/atomic.rs b/src/libcore/atomic.rs index d738ff947c498..ed35e09549217 100644 --- a/src/libcore/atomic.rs +++ b/src/libcore/atomic.rs @@ -122,7 +122,7 @@ unsafe impl Sync for AtomicPtr {} /// Rust's memory orderings are [the same as /// C++'s](http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync). #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Ordering { /// No ordering constraints, only atomic operations. #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/error.rs b/src/libcore/error.rs deleted file mode 100644 index 24035b7d9a83b..0000000000000 --- a/src/libcore/error.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Traits for working with Errors. -//! -//! # The `Error` trait -//! -//! `Error` is a trait representing the basic expectations for error values, -//! i.e. values of type `E` in `Result`. At a minimum, errors must provide -//! a description, but they may optionally provide additional detail (via -//! `Display`) and cause chain information: -//! -//! ``` -//! use std::fmt::Display; -//! -//! trait Error: Display { -//! fn description(&self) -> &str; -//! -//! fn cause(&self) -> Option<&Error> { None } -//! } -//! ``` -//! -//! The `cause` method is generally used when errors cross "abstraction -//! boundaries", i.e. when a one module must report an error that is "caused" -//! by an error from a lower-level module. This setup makes it possible for the -//! high-level module to provide its own errors that do not commit to any -//! particular implementation, but also reveal some of its implementation for -//! debugging via `cause` chains. - -#![stable(feature = "rust1", since = "1.0.0")] - -use prelude::*; -use fmt::{Debug, Display}; - -/// Base functionality for all errors in Rust. -#[stable(feature = "rust1", since = "1.0.0")] -pub trait Error: Debug + Display { - /// A short description of the error. - /// - /// The description should not contain newlines or sentence-ending - /// punctuation, to facilitate embedding in larger user-facing - /// strings. - #[stable(feature = "rust1", since = "1.0.0")] - fn description(&self) -> &str; - - /// The lower-level cause of this error, if any. - #[stable(feature = "rust1", since = "1.0.0")] - fn cause(&self) -> Option<&Error> { None } -} diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index ffb358cdac84d..be804327663e5 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -12,9 +12,9 @@ #![stable(feature = "rust1", since = "1.0.0")] -use any; use cell::{Cell, RefCell, Ref, RefMut, BorrowState}; use char::CharExt; +use clone::Clone; use iter::Iterator; use marker::{Copy, PhantomData, Sized}; use mem; @@ -54,7 +54,7 @@ pub type Result = result::Result<(), Error>; /// occurred. Any extra information must be arranged to be transmitted through /// some other means. #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Error; /// A collection of methods that are required to format a message into a stream. @@ -141,6 +141,12 @@ pub struct ArgumentV1<'a> { formatter: fn(&Void, &mut Formatter) -> Result, } +impl<'a> Clone for ArgumentV1<'a> { + fn clone(&self) -> ArgumentV1<'a> { + *self + } +} + impl<'a> ArgumentV1<'a> { #[inline(never)] fn show_usize(x: &usize, f: &mut Formatter) -> Result { @@ -175,7 +181,7 @@ impl<'a> ArgumentV1<'a> { } // flags available in the v1 format of format_args -#[derive(Copy)] +#[derive(Copy, Clone)] #[allow(dead_code)] // SignMinus isn't currently used enum FlagV1 { SignPlus, SignMinus, Alternate, SignAwareZeroPad, } @@ -222,7 +228,7 @@ impl<'a> Arguments<'a> { /// macro validates the format string at compile-time so usage of the `write` /// and `format` functions can be safely performed. #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Arguments<'a> { // Format string pieces to print. pieces: &'a [&'a str], @@ -997,11 +1003,6 @@ macro_rules! tuple { tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Debug for &'a (any::Any+'a) { - fn fmt(&self, f: &mut Formatter) -> Result { f.pad("&Any") } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Debug for [T] { fn fmt(&self, f: &mut Formatter) -> Result { diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index f3f5a0b70cb74..76c975902aabb 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -139,7 +139,7 @@ impl GenericRadix for Radix { /// A helper type for formatting radixes. #[unstable(feature = "core", reason = "may be renamed or move to a different module")] -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct RadixFmt(T, R); /// Constructs a radix formatter in the range of `2..36`. diff --git a/src/libcore/fmt/rt/v1.rs b/src/libcore/fmt/rt/v1.rs index 7f6dea905dafd..d56ec6a74d449 100644 --- a/src/libcore/fmt/rt/v1.rs +++ b/src/libcore/fmt/rt/v1.rs @@ -16,7 +16,7 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[derive(Copy)] +#[derive(Copy, Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Argument { #[stable(feature = "rust1", since = "1.0.0")] @@ -25,7 +25,7 @@ pub struct Argument { pub format: FormatSpec, } -#[derive(Copy)] +#[derive(Copy, Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct FormatSpec { #[stable(feature = "rust1", since = "1.0.0")] @@ -41,7 +41,7 @@ pub struct FormatSpec { } /// Possible alignments that can be requested as part of a formatting directive. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Alignment { /// Indication that contents should be left-aligned. @@ -58,7 +58,7 @@ pub enum Alignment { Unknown, } -#[derive(Copy)] +#[derive(Copy, Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Count { #[stable(feature = "rust1", since = "1.0.0")] @@ -71,7 +71,7 @@ pub enum Count { Implied, } -#[derive(Copy)] +#[derive(Copy, Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Position { #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 2d69eeb9fa962..42e90ec34db7c 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -45,10 +45,8 @@ //! let mut it = values.into_iter(); //! loop { //! match it.next() { -//! Some(x) => { -//! println!("{}", x); -//! } -//! None => { break } +//! Some(x) => println!("{}", x), +//! None => break, //! } //! } //! ``` diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 5e8b7fba1f15c..2189e2c3ad1ba 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -70,8 +70,10 @@ #![feature(unboxed_closures)] #![feature(rustc_attrs)] #![feature(optin_builtin_traits)] +#![feature(fundamental)] #![feature(concat_idents)] #![feature(reflect)] +#![feature(custom_attribute)] #[macro_use] mod macros; @@ -145,7 +147,6 @@ pub mod slice; pub mod str; pub mod hash; pub mod fmt; -pub mod error; #[doc(primitive = "bool")] mod bool { diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index f755c912fcd4a..619f983aee071 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -49,6 +49,7 @@ impl !Send for Managed { } #[stable(feature = "rust1", since = "1.0.0")] #[lang="sized"] #[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] +#[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized : MarkerTrait { // Empty. } @@ -75,7 +76,7 @@ pub trait Sized : MarkerTrait { /// /// ``` /// // we can just derive a `Copy` implementation -/// #[derive(Debug, Copy)] +/// #[derive(Debug, Copy, Clone)] /// struct Foo; /// /// let x = Foo; @@ -124,7 +125,7 @@ pub trait Sized : MarkerTrait { /// There are two ways to implement `Copy` on your type: /// /// ``` -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct MyStruct; /// ``` /// @@ -133,6 +134,7 @@ pub trait Sized : MarkerTrait { /// ``` /// struct MyStruct; /// impl Copy for MyStruct {} +/// impl Clone for MyStruct { fn clone(&self) -> MyStruct { *self } } /// ``` /// /// There is a small difference between the two: the `derive` strategy will also place a `Copy` @@ -154,7 +156,7 @@ pub trait Sized : MarkerTrait { /// change: that second example would fail to compile if we made `Foo` non-`Copy`. #[stable(feature = "rust1", since = "1.0.0")] #[lang="copy"] -pub trait Copy : MarkerTrait { +pub trait Copy : Clone { // Empty. } @@ -346,17 +348,16 @@ impl MarkerTrait for T { } #[stable(feature = "rust1", since = "1.0.0")] pub trait PhantomFn { } -/// `PhantomData` is a way to tell the compiler about fake fields. -/// Phantom data is required whenever type parameters are not used. -/// The idea is that if the compiler encounters a `PhantomData` -/// instance, it will behave *as if* an instance of the type `T` were -/// present for the purpose of various automatic analyses. +/// `PhantomData` allows you to describe that a type acts as if it stores a value of type `T`, +/// even though it does not. This allows you to inform the compiler about certain safety properties +/// of your code. +/// +/// Though they both have scary names, `PhantomData` and "phantom types" are unrelated. 👻👻👻 /// /// # Examples /// /// When handling external resources over a foreign function interface, `PhantomData` can -/// prevent mismatches by enforcing types in the method implementations, although the struct -/// doesn't actually contain values of the resource type. +/// prevent mismatches by enforcing types in the method implementations: /// /// ``` /// # trait ResType { fn foo(&self); }; @@ -397,11 +398,6 @@ pub trait PhantomFn { } /// commonly necessary if the structure is using an unsafe pointer /// like `*mut T` whose referent may be dropped when the type is /// dropped, as a `*mut T` is otherwise not treated as owned. -/// -/// FIXME. Better documentation and examples of common patterns needed -/// here! For now, please see [RFC 738][738] for more information. -/// -/// [738]: https://github.com/rust-lang/rfcs/blob/master/text/0738-variance.md #[lang="phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index 13f168b3fdbe1..28e0bcf13dd09 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -20,7 +20,6 @@ use self::wrapping::{OverflowingOps, WrappingOps}; use char::CharExt; use clone::Clone; use cmp::{PartialEq, Eq, PartialOrd, Ord}; -use error::Error; use fmt; use intrinsics; use iter::Iterator; @@ -820,6 +819,18 @@ macro_rules! int_impl { $add_with_overflow:path, $sub_with_overflow:path, $mul_with_overflow:path) => { + /// Returns the smallest value that can be represented by this integer type. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn min_value() -> $T { + (-1 as $T) << ($BITS - 1) + } + + /// Returns the largest value that can be represented by this integer type. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn max_value() -> $T { + let min: $T = Int::min_value(); !min + } + /// Convert a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. @@ -1330,6 +1341,14 @@ macro_rules! uint_impl { $add_with_overflow:path, $sub_with_overflow:path, $mul_with_overflow:path) => { + /// Returns the smallest value that can be represented by this integer type. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn min_value() -> $T { 0 } + + /// Returns the largest value that can be represented by this integer type. + #[stable(feature = "rust1", since = "1.0.0")] + pub fn max_value() -> $T { !0 } + /// Convert a string slice in a given base to an integer. /// /// Leading and trailing whitespace represent an error. @@ -2425,7 +2444,7 @@ impl_num_cast! { f32, to_f32 } impl_num_cast! { f64, to_f64 } /// Used for representing the classification of floating point numbers -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub enum FpCategory { /// "Not a Number", often obtained by dividing by zero @@ -2948,16 +2967,9 @@ enum IntErrorKind { Underflow, } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseIntError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseIntError { - fn description(&self) -> &str { +impl ParseIntError { + #[unstable(feature = "core", reason = "available through Error trait")] + pub fn description(&self) -> &str { match self.kind { IntErrorKind::Empty => "cannot parse integer from empty string", IntErrorKind::InvalidDigit => "invalid digit found in string", @@ -2967,6 +2979,13 @@ impl Error for ParseIntError { } } +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} + /// An error which can be returned when parsing a float. #[derive(Debug, Clone, PartialEq)] #[stable(feature = "rust1", since = "1.0.0")] @@ -2978,19 +2997,19 @@ enum FloatErrorKind { Invalid, } -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseFloatError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseFloatError { - fn description(&self) -> &str { +impl ParseFloatError { + #[unstable(feature = "core", reason = "available through Error trait")] + pub fn description(&self) -> &str { match self.kind { FloatErrorKind::Empty => "cannot parse float from empty string", FloatErrorKind::Invalid => "invalid float literal", } } } + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseFloatError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.description().fmt(f) + } +} diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 277f7db8fd4b1..faf305c6a1378 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -165,7 +165,7 @@ macro_rules! forward_ref_binop { /// ``` /// use std::ops::Add; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Add for Foo { @@ -219,7 +219,7 @@ add_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// ``` /// use std::ops::Sub; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Sub for Foo { @@ -273,7 +273,7 @@ sub_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// ``` /// use std::ops::Mul; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Mul for Foo { @@ -327,7 +327,7 @@ mul_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// ``` /// use std::ops::Div; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Div for Foo { @@ -381,7 +381,7 @@ div_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 f32 f64 } /// ``` /// use std::ops::Rem; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Rem for Foo { @@ -454,7 +454,7 @@ rem_float_impl! { f64, fmod } /// ``` /// use std::ops::Neg; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Neg for Foo { @@ -527,7 +527,7 @@ neg_impl_numeric! { isize i8 i16 i32 i64 f32 f64 } /// ``` /// use std::ops::Not; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Not for Foo { @@ -581,7 +581,7 @@ not_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// ``` /// use std::ops::BitAnd; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl BitAnd for Foo { @@ -635,7 +635,7 @@ bitand_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// ``` /// use std::ops::BitOr; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl BitOr for Foo { @@ -689,7 +689,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// ``` /// use std::ops::BitXor; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl BitXor for Foo { @@ -743,7 +743,7 @@ bitxor_impl! { bool usize u8 u16 u32 u64 isize i8 i16 i32 i64 } /// ``` /// use std::ops::Shl; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Shl for Foo { @@ -815,7 +815,7 @@ shl_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// ``` /// use std::ops::Shr; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// /// impl Shr for Foo { @@ -887,7 +887,7 @@ shr_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } /// ``` /// use std::ops::Index; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// struct Bar; /// @@ -928,7 +928,7 @@ pub trait Index { /// ``` /// use std::ops::{Index, IndexMut}; /// -/// #[derive(Copy)] +/// #[derive(Copy, Clone)] /// struct Foo; /// struct Bar; /// @@ -1133,6 +1133,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T { #[lang="fn"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait Fn : FnMut { /// This is called when the call operator is used. extern "rust-call" fn call(&self, args: Args) -> Self::Output; @@ -1142,6 +1143,7 @@ pub trait Fn : FnMut { #[lang="fn_mut"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnMut : FnOnce { /// This is called when the call operator is used. extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; @@ -1151,6 +1153,7 @@ pub trait FnMut : FnOnce { #[lang="fn_once"] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_paren_sugar] +#[fundamental] // so that regex can rely that `&str: !FnMut` pub trait FnOnce { /// The returned type after the call operator is used. type Output; @@ -1158,3 +1161,52 @@ pub trait FnOnce { /// This is called when the call operator is used. extern "rust-call" fn call_once(self, args: Args) -> Self::Output; } + +#[cfg(not(stage0))] +mod impls { + use marker::Sized; + use super::{Fn, FnMut, FnOnce}; + + impl<'a,A,F:?Sized> Fn for &'a F + where F : Fn + { + extern "rust-call" fn call(&self, args: A) -> F::Output { + (**self).call(args) + } + } + + impl<'a,A,F:?Sized> FnMut for &'a F + where F : Fn + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (**self).call(args) + } + } + + impl<'a,A,F:?Sized> FnOnce for &'a F + where F : Fn + { + type Output = F::Output; + + extern "rust-call" fn call_once(self, args: A) -> F::Output { + (*self).call(args) + } + } + + impl<'a,A,F:?Sized> FnMut for &'a mut F + where F : FnMut + { + extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } + + impl<'a,A,F:?Sized> FnOnce for &'a mut F + where F : FnMut + { + type Output = F::Output; + extern "rust-call" fn call_once(mut self, args: A) -> F::Output { + (*self).call_mut(args) + } + } +} diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index 47d1f3a1a3ccf..ded52ff07785e 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -18,6 +18,7 @@ //! //! Their definition should always match the ABI defined in `rustc::back::abi`. +use clone::Clone; use marker::Copy; use mem; @@ -63,6 +64,9 @@ pub struct Slice { } impl Copy for Slice {} +impl Clone for Slice { + fn clone(&self) -> Slice { *self } +} /// The representation of a trait object like `&SomeTrait`. /// @@ -136,7 +140,7 @@ impl Copy for Slice {} /// assert_eq!(synthesized.bar(), 457); /// ``` #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct TraitObject { pub data: *mut (), pub vtable: *mut (), diff --git a/src/libcore/simd.rs b/src/libcore/simd.rs index 21cff3021abea..7b55ba49a07f7 100644 --- a/src/libcore/simd.rs +++ b/src/libcore/simd.rs @@ -38,7 +38,7 @@ #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i8x16(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, @@ -47,26 +47,26 @@ pub struct i8x16(pub i8, pub i8, pub i8, pub i8, #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i16x8(pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16, pub i16); #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i32x4(pub i32, pub i32, pub i32, pub i32); #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct i64x2(pub i64, pub i64); #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u8x16(pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, pub u8, @@ -75,31 +75,31 @@ pub struct u8x16(pub u8, pub u8, pub u8, pub u8, #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u16x8(pub u16, pub u16, pub u16, pub u16, pub u16, pub u16, pub u16, pub u16); #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u32x4(pub u32, pub u32, pub u32, pub u32); #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct u64x2(pub u64, pub u64); #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct f32x4(pub f32, pub f32, pub f32, pub f32); #[unstable(feature = "core")] #[simd] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[repr(C)] pub struct f64x2(pub f64, pub f64); diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index d8856130fab33..70e60adf64c2a 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1126,18 +1126,20 @@ impl> Iterator for GenericSplitN { #[inline] fn next(&mut self) -> Option { - if self.count == 0 { - self.iter.finish() - } else { - self.count -= 1; - if self.invert { self.iter.next_back() } else { self.iter.next() } + match self.count { + 0 => None, + 1 => { self.count -= 1; self.iter.finish() } + _ => { + self.count -= 1; + if self.invert {self.iter.next_back()} else {self.iter.next()} + } } } #[inline] fn size_hint(&self) -> (usize, Option) { let (lower, upper_opt) = self.iter.size_hint(); - (lower, upper_opt.map(|upper| cmp::min(self.count + 1, upper))) + (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) } } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index c78fa80336153..dbb365c4e2357 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -22,7 +22,6 @@ use char::CharExt; use clone::Clone; use cmp::{self, Eq}; use default::Default; -use error::Error; use fmt; use iter::ExactSizeIterator; use iter::{Map, Iterator, DoubleEndedIterator}; @@ -192,11 +191,6 @@ impl fmt::Display for ParseBoolError { } } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for ParseBoolError { - fn description(&self) -> &str { "failed to parse bool" } -} - /* Section: Creating a string */ @@ -241,16 +235,6 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str { mem::transmute(v) } -#[stable(feature = "rust1", since = "1.0.0")] -impl Error for Utf8Error { - fn description(&self) -> &str { - match *self { - Utf8Error::TooShort => "invalid utf-8: not enough bytes", - Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", - } - } -} - #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Utf8Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -505,7 +489,7 @@ struct CharSplits<'a, P: Pattern<'a>> { /// splitting at most `count` times. struct CharSplitsN<'a, P: Pattern<'a>> { iter: CharSplits<'a, P>, - /// The number of splits remaining + /// The number of items remaining count: usize, } @@ -612,11 +596,10 @@ impl<'a, P: Pattern<'a>> Iterator for CharSplitsN<'a, P> { #[inline] fn next(&mut self) -> Option<&'a str> { - if self.count != 0 { - self.count -= 1; - self.iter.next() - } else { - self.iter.get_end() + match self.count { + 0 => None, + 1 => { self.count = 0; self.iter.get_end() } + _ => { self.count -= 1; self.iter.next() } } } } @@ -666,11 +649,10 @@ impl<'a, P: Pattern<'a>> Iterator for RCharSplitsN<'a, P> #[inline] fn next(&mut self) -> Option<&'a str> { - if self.count != 0 { - self.count -= 1; - self.iter.next() - } else { - self.iter.get_remainder() + match self.count { + 0 => None, + 1 => { self.count -= 1; self.iter.get_remainder() } + _ => { self.count -= 1; self.iter.next() } } } } @@ -1123,7 +1105,7 @@ static UTF8_CHAR_WIDTH: [u8; 256] = [ /// Struct that contains a `char` and the index of the first byte of /// the next `char` in a string. This can be used as a data structure /// for iterating over the UTF-8 bytes of a string. -#[derive(Copy)] +#[derive(Copy, Clone)] #[unstable(feature = "str_char", reason = "existence of this struct is uncertain as it is frequently \ able to be replaced with char.len_utf8() and/or \ diff --git a/src/libcoretest/str.rs b/src/libcoretest/str.rs index c935b5545740c..5fce527d9798d 100644 --- a/src/libcoretest/str.rs +++ b/src/libcoretest/str.rs @@ -65,20 +65,20 @@ fn test_strslice_contains() { fn test_rsplitn_char_iterator() { let data = "\nMäry häd ä little lämb\nLittle lämb\n"; - let mut split: Vec<&str> = data.rsplitn(3, ' ').collect(); + let mut split: Vec<&str> = data.rsplitn(4, ' ').collect(); split.reverse(); 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(); + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == ' ').collect(); split.reverse(); assert_eq!(split, ["\nMäry häd ä", "little", "lämb\nLittle", "lämb\n"]); // Unicode - let mut split: Vec<&str> = data.rsplitn(3, 'ä').collect(); + let mut split: Vec<&str> = data.rsplitn(4, 'ä').collect(); split.reverse(); 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(); + let mut split: Vec<&str> = data.rsplitn(4, |c: char| c == 'ä').collect(); split.reverse(); assert_eq!(split, ["\nMäry häd ", " little l", "mb\nLittle l", "mb\n"]); } diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index a7be6a7fcf07a..4cf93ab2645df 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -40,7 +40,7 @@ use std::string; /// A piece is a portion of the format string which represents the next part /// to emit. These are emitted as a stream by the `Parser` class. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum Piece<'a> { /// A literal string which should directly be emitted String(&'a str), @@ -50,7 +50,7 @@ pub enum Piece<'a> { } /// Representation of an argument specification. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub struct Argument<'a> { /// Where to find this argument pub position: Position<'a>, @@ -59,7 +59,7 @@ pub struct Argument<'a> { } /// Specification for the formatting of an argument in the format string. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub struct FormatSpec<'a> { /// Optionally specified character to fill alignment with pub fill: Option, @@ -78,7 +78,7 @@ pub struct FormatSpec<'a> { } /// Enum describing where an argument for a format can be located. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum Position<'a> { /// The argument will be in the next position. This is the default. ArgumentNext, @@ -89,7 +89,7 @@ pub enum Position<'a> { } /// Enum of alignments which are supported. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum Alignment { /// The value will be aligned to the left. AlignLeft, @@ -103,7 +103,7 @@ pub enum Alignment { /// Various flags which can be applied to format strings. The meaning of these /// flags is defined by the formatters themselves. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum Flag { /// A `+` will be used to denote positive numbers. FlagSignPlus, @@ -119,7 +119,7 @@ pub enum Flag { /// A count is used for the precision and width parameters of an integer, and /// can reference either an argument or a literal integer. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum Count<'a> { /// The count is specified explicitly. CountIs(usize), diff --git a/src/libgetopts/lib.rs b/src/libgetopts/lib.rs index 9a5dde8e45e2f..5c10641e8515e 100644 --- a/src/libgetopts/lib.rs +++ b/src/libgetopts/lib.rs @@ -213,7 +213,7 @@ pub enum Fail { } /// The type of failure that occurred. -#[derive(Copy, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] #[allow(missing_docs)] pub enum FailType { ArgumentMissing_, @@ -843,18 +843,18 @@ pub fn short_usage(program_name: &str, opts: &[OptGroup]) -> String { line } -#[derive(Copy)] +#[derive(Copy, Clone)] enum SplitWithinState { A, // leading whitespace, initial state B, // words C, // internal and trailing whitespace } -#[derive(Copy)] +#[derive(Copy, Clone)] enum Whitespace { Ws, // current char is whitespace Cr // current char is not whitespace } -#[derive(Copy)] +#[derive(Copy, Clone)] enum LengthLimit { UnderLim, // current char makes current substring still fit in limit OverLim // current char makes current substring no longer fit in limit diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs index 74be96235d2d7..95b78e1cbfd03 100644 --- a/src/libgraphviz/lib.rs +++ b/src/libgraphviz/lib.rs @@ -524,7 +524,7 @@ pub trait GraphWalk<'a, N, E> { fn target(&'a self, edge: &E) -> N; } -#[derive(Copy, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum RenderOption { NoEdgeLabels, NoNodeLabels, diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index bfc657f8784cc..44d689059d1cf 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -227,7 +227,7 @@ pub mod types { pub type rlim_t = u64; #[repr(C)] - #[derive(Copy)] pub struct glob_t { + #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: size_t, pub gl_pathv: *mut *mut c_char, pub gl_offs: size_t, @@ -240,23 +240,23 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct timeval { + #[derive(Copy, Clone)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy)] pub struct timespec { + #[derive(Copy, Clone)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } - #[derive(Copy)] pub enum timezone {} + pub enum timezone {} pub type sighandler_t = size_t; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rlimit { pub rlim_cur: rlim_t, pub rlim_max: rlim_t, @@ -269,7 +269,7 @@ pub mod types { // This is also specified in POSIX 2001, but only has two fields. All implementors // implement BSD 4.3 version. #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rusage { pub ru_utime: timeval, pub ru_stime: timeval, @@ -299,7 +299,7 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy)] pub struct sockaddr { + #[derive(Copy, Clone)] pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8; 14], } @@ -312,19 +312,22 @@ pub mod types { #[cfg(target_pointer_width = "64")] pub __ss_pad2: [u8; 128 - 2 * 8], } + impl ::core::clone::Clone for sockaddr_storage { + fn clone(&self) -> sockaddr_storage { *self } + } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in { + #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy)] pub struct in_addr { + #[derive(Copy, Clone)] pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, pub sin6_flowinfo: u32, @@ -332,21 +335,21 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy)] pub struct in6_addr { + #[derive(Copy, Clone)] pub struct in6_addr { pub s6_addr: [u16; 8] } #[repr(C)] - #[derive(Copy)] pub struct ip_mreq { + #[derive(Copy, Clone)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy)] pub struct ip6_mreq { + #[derive(Copy, Clone)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy)] pub struct addrinfo { + #[derive(Copy, Clone)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -372,9 +375,12 @@ pub mod types { pub sun_family: sa_family_t, pub sun_path: [c_char; 108] } + impl ::core::clone::Clone for sockaddr_un { + fn clone(&self) -> sockaddr_un { *self } + } #[repr(C)] - #[derive(Copy)] pub struct ifaddrs { + #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, @@ -465,7 +471,7 @@ pub mod types { pub type blkcnt_t = i32; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: dev_t, pub __pad1: c_short, pub st_ino: ino_t, @@ -489,13 +495,13 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy)] pub struct pthread_attr_t { + #[derive(Copy, Clone)] pub struct pthread_attr_t { pub __size: [u32; 9] } } @@ -510,7 +516,7 @@ pub mod types { pub type blkcnt_t = u32; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: c_ulonglong, pub __pad0: [c_uchar; 4], pub __st_ino: ino_t, @@ -533,13 +539,13 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy)] pub struct pthread_attr_t { + #[derive(Copy, Clone)] pub struct pthread_attr_t { pub __size: [u32; 9] } } @@ -556,7 +562,7 @@ pub mod types { pub type blkcnt_t = i32; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: c_ulong, pub st_pad1: [c_long; 3], pub st_ino: ino_t, @@ -580,13 +586,13 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy)] pub struct pthread_attr_t { + #[derive(Copy, Clone)] pub struct pthread_attr_t { pub __size: [u32; 9] } } @@ -595,7 +601,7 @@ pub mod types { pub mod extra { use types::os::arch::c95::{c_ushort, c_int, c_uchar}; #[repr(C)] - #[derive(Copy)] pub struct sockaddr_ll { + #[derive(Copy, Clone)] pub struct sockaddr_ll { pub sll_family: c_ushort, pub sll_protocol: c_ushort, pub sll_ifindex: c_int, @@ -667,7 +673,7 @@ pub mod types { pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_nlink: nlink_t, @@ -689,13 +695,13 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy)] pub struct pthread_attr_t { + #[derive(Copy, Clone)] pub struct pthread_attr_t { pub __size: [u64; 7] } } @@ -711,7 +717,7 @@ pub mod types { pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_mode: mode_t, @@ -734,13 +740,13 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } #[repr(C)] - #[derive(Copy)] pub struct pthread_attr_t { + #[derive(Copy, Clone)] pub struct pthread_attr_t { pub __size: [u64; 8] } } @@ -750,7 +756,7 @@ pub mod types { } pub mod extra { use types::os::arch::c95::{c_ushort, c_int, c_uchar}; - #[derive(Copy)] pub struct sockaddr_ll { + #[derive(Copy, Clone)] pub struct sockaddr_ll { pub sll_family: c_ushort, pub sll_protocol: c_ushort, pub sll_ifindex: c_int, @@ -777,7 +783,7 @@ pub mod types { pub type rlim_t = i64; #[repr(C)] - #[derive(Copy)] pub struct glob_t { + #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: size_t, pub gl_offs: size_t, @@ -794,23 +800,23 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct timeval { + #[derive(Copy, Clone)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy)] pub struct timespec { + #[derive(Copy, Clone)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } - #[derive(Copy)] pub enum timezone {} + pub enum timezone {} pub type sighandler_t = size_t; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rlimit { pub rlim_cur: rlim_t, pub rlim_max: rlim_t, @@ -821,7 +827,7 @@ pub mod types { use types::os::common::posix01::timeval; use types::os::arch::c95::c_long; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rusage { pub ru_utime: timeval, pub ru_stime: timeval, @@ -851,13 +857,13 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy)] pub struct sockaddr { + #[derive(Copy, Clone)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy, Clone)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], @@ -865,7 +871,7 @@ pub mod types { pub __ss_pad2: [u8; 112], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in { + #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -873,11 +879,11 @@ pub mod types { pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy)] pub struct in_addr { + #[derive(Copy, Clone)] pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -886,21 +892,21 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy)] pub struct in6_addr { + #[derive(Copy, Clone)] pub struct in6_addr { pub s6_addr: [u16; 8] } #[repr(C)] - #[derive(Copy)] pub struct ip_mreq { + #[derive(Copy, Clone)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy)] pub struct ip6_mreq { + #[derive(Copy, Clone)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy)] pub struct addrinfo { + #[derive(Copy, Clone)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -911,13 +917,13 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy, Clone)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } #[repr(C)] - #[derive(Copy)] pub struct ifaddrs { + #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, @@ -984,7 +990,7 @@ pub mod types { pub type blkcnt_t = i64; pub type fflags_t = u32; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_mode: mode_t, @@ -1010,7 +1016,7 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -1039,7 +1045,7 @@ pub mod types { pub type rlim_t = i64; #[repr(C)] - #[derive(Copy)] pub struct glob_t { + #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: size_t, pub gl_offs: size_t, @@ -1056,23 +1062,23 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct timeval { + #[derive(Copy, Clone)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy)] pub struct timespec { + #[derive(Copy, Clone)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } - #[derive(Copy)] pub enum timezone {} + pub enum timezone {} pub type sighandler_t = size_t; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rlimit { pub rlim_cur: rlim_t, pub rlim_max: rlim_t, @@ -1083,7 +1089,7 @@ pub mod types { use types::os::common::posix01::timeval; use types::os::arch::c95::c_long; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rusage { pub ru_utime: timeval, pub ru_stime: timeval, @@ -1113,13 +1119,13 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy)] pub struct sockaddr { + #[derive(Copy, Clone)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy, Clone)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], @@ -1127,7 +1133,7 @@ pub mod types { pub __ss_pad2: [u8; 112], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in { + #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -1135,11 +1141,11 @@ pub mod types { pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy)] pub struct in_addr { + #[derive(Copy, Clone)] pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -1148,21 +1154,21 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy)] pub struct in6_addr { + #[derive(Copy, Clone)] pub struct in6_addr { pub s6_addr: [u16; 8] } #[repr(C)] - #[derive(Copy)] pub struct ip_mreq { + #[derive(Copy, Clone)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy)] pub struct ip6_mreq { + #[derive(Copy, Clone)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy)] pub struct addrinfo { + #[derive(Copy, Clone)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -1173,13 +1179,13 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy, Clone)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } #[repr(C)] - #[derive(Copy)] pub struct ifaddrs { + #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, @@ -1246,7 +1252,7 @@ pub mod types { pub type fflags_t = u32; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_ino: ino_t, pub st_nlink: nlink_t, pub st_dev: dev_t, @@ -1271,7 +1277,7 @@ pub mod types { pub st_qspare2: int64_t, } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -1301,7 +1307,7 @@ pub mod types { #[cfg(target_os = "bitrig")] #[repr(C)] - #[derive(Copy)] pub struct glob_t { + #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: c_int, pub gl_matchc: c_int, pub gl_offs: c_int, @@ -1318,7 +1324,7 @@ pub mod types { #[cfg(target_os = "openbsd")] #[repr(C)] - #[derive(Copy)] pub struct glob_t { + #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: c_int, pub __unused1: c_int, pub gl_offs: c_int, @@ -1336,23 +1342,23 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct timeval { + #[derive(Copy, Clone)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy)] pub struct timespec { + #[derive(Copy, Clone)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } - #[derive(Copy)] pub enum timezone {} + pub enum timezone {} pub type sighandler_t = size_t; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rlimit { pub rlim_cur: rlim_t, pub rlim_max: rlim_t, @@ -1363,7 +1369,7 @@ pub mod types { use types::os::common::posix01::timeval; use types::os::arch::c95::c_long; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rusage { pub ru_utime: timeval, pub ru_stime: timeval, @@ -1393,13 +1399,13 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy)] pub struct sockaddr { + #[derive(Copy, Clone)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_storage { + #[derive(Copy, Clone)] pub struct sockaddr_storage { pub ss_len: u8, pub ss_family: sa_family_t, pub __ss_pad1: [u8; 6], @@ -1407,7 +1413,7 @@ pub mod types { pub __ss_pad3: [u8; 240], } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in { + #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -1415,11 +1421,11 @@ pub mod types { pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy)] pub struct in_addr { + #[derive(Copy, Clone)] pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -1428,21 +1434,21 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy)] pub struct in6_addr { + #[derive(Copy, Clone)] pub struct in6_addr { pub s6_addr: [u16; 8] } #[repr(C)] - #[derive(Copy)] pub struct ip_mreq { + #[derive(Copy, Clone)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy)] pub struct ip6_mreq { + #[derive(Copy, Clone)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy)] pub struct addrinfo { + #[derive(Copy, Clone)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -1453,13 +1459,13 @@ pub mod types { pub ai_next: *mut addrinfo, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_un { + #[derive(Copy, Clone)] pub struct sockaddr_un { pub sun_len: u8, pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } #[repr(C)] - #[derive(Copy)] pub struct ifaddrs { + #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, @@ -1526,7 +1532,7 @@ pub mod types { pub type fflags_t = u32; // type not declared, but struct stat have u_int32_t #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_mode: mode_t, pub st_dev: dev_t, pub st_ino: ino_t, @@ -1549,7 +1555,7 @@ pub mod types { pub st_birthtime_nsec: c_long, } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -1576,7 +1582,7 @@ pub mod types { // pub Note: this is the struct called stat64 in Windows. Not stat, // nor stati64. #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: dev_t, pub st_ino: ino_t, pub st_mode: u16, @@ -1592,24 +1598,24 @@ pub mod types { // note that this is called utimbuf64 in Windows #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time64_t, pub modtime: time64_t, } #[repr(C)] - #[derive(Copy)] pub struct timeval { + #[derive(Copy, Clone)] pub struct timeval { pub tv_sec: c_long, pub tv_usec: c_long, } #[repr(C)] - #[derive(Copy)] pub struct timespec { + #[derive(Copy, Clone)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } - #[derive(Copy)] pub enum timezone {} + pub enum timezone {} } pub mod bsd44 { @@ -1622,7 +1628,7 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy)] pub struct sockaddr { + #[derive(Copy, Clone)] pub struct sockaddr { pub sa_family: sa_family_t, pub sa_data: [u8; 14], } @@ -1633,19 +1639,22 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8; 112], } + impl ::core::clone::Clone for sockaddr_storage { + fn clone(&self) -> sockaddr_storage { *self } + } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in { + #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_family: sa_family_t, pub sin_port: in_port_t, pub sin_addr: in_addr, pub sin_zero: [u8; 8], } #[repr(C)] - #[derive(Copy)] pub struct in_addr { + #[derive(Copy, Clone)] pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_family: sa_family_t, pub sin6_port: in_port_t, pub sin6_flowinfo: u32, @@ -1653,21 +1662,21 @@ pub mod types { pub sin6_scope_id: u32, } #[repr(C)] - #[derive(Copy)] pub struct in6_addr { + #[derive(Copy, Clone)] pub struct in6_addr { pub s6_addr: [u16; 8] } #[repr(C)] - #[derive(Copy)] pub struct ip_mreq { + #[derive(Copy, Clone)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy)] pub struct ip6_mreq { + #[derive(Copy, Clone)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy)] pub struct addrinfo { + #[derive(Copy, Clone)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -1682,6 +1691,9 @@ pub mod types { pub sun_family: sa_family_t, pub sun_path: [c_char; 108] } + impl ::core::clone::Clone for sockaddr_un { + fn clone(&self) -> sockaddr_un { *self } + } } } @@ -1807,7 +1819,7 @@ pub mod types { pub type LPCH = *mut CHAR; #[repr(C)] - #[derive(Copy)] pub struct SECURITY_ATTRIBUTES { + #[derive(Copy, Clone)] pub struct SECURITY_ATTRIBUTES { pub nLength: DWORD, pub lpSecurityDescriptor: LPVOID, pub bInheritHandle: BOOL, @@ -1831,7 +1843,7 @@ pub mod types { pub type int64 = i64; #[repr(C)] - #[derive(Copy)] pub struct STARTUPINFO { + #[derive(Copy, Clone)] pub struct STARTUPINFO { pub cb: DWORD, pub lpReserved: LPWSTR, pub lpDesktop: LPWSTR, @@ -1854,7 +1866,7 @@ pub mod types { pub type LPSTARTUPINFO = *mut STARTUPINFO; #[repr(C)] - #[derive(Copy)] pub struct PROCESS_INFORMATION { + #[derive(Copy, Clone)] pub struct PROCESS_INFORMATION { pub hProcess: HANDLE, pub hThread: HANDLE, pub dwProcessId: DWORD, @@ -1863,7 +1875,7 @@ pub mod types { pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; #[repr(C)] - #[derive(Copy)] pub struct SYSTEM_INFO { + #[derive(Copy, Clone)] pub struct SYSTEM_INFO { pub wProcessorArchitecture: WORD, pub wReserved: WORD, pub dwPageSize: DWORD, @@ -1879,7 +1891,7 @@ pub mod types { pub type LPSYSTEM_INFO = *mut SYSTEM_INFO; #[repr(C)] - #[derive(Copy)] pub struct MEMORY_BASIC_INFORMATION { + #[derive(Copy, Clone)] pub struct MEMORY_BASIC_INFORMATION { pub BaseAddress: LPVOID, pub AllocationBase: LPVOID, pub AllocationProtect: DWORD, @@ -1891,7 +1903,7 @@ pub mod types { pub type LPMEMORY_BASIC_INFORMATION = *mut MEMORY_BASIC_INFORMATION; #[repr(C)] - #[derive(Copy)] pub struct OVERLAPPED { + #[derive(Copy, Clone)] pub struct OVERLAPPED { pub Internal: *mut c_ulong, pub InternalHigh: *mut c_ulong, pub Offset: DWORD, @@ -1902,7 +1914,7 @@ pub mod types { pub type LPOVERLAPPED = *mut OVERLAPPED; #[repr(C)] - #[derive(Copy)] pub struct FILETIME { + #[derive(Copy, Clone)] pub struct FILETIME { pub dwLowDateTime: DWORD, pub dwHighDateTime: DWORD, } @@ -1910,7 +1922,7 @@ pub mod types { pub type LPFILETIME = *mut FILETIME; #[repr(C)] - #[derive(Copy)] pub struct GUID { + #[derive(Copy, Clone)] pub struct GUID { pub Data1: DWORD, pub Data2: WORD, pub Data3: WORD, @@ -1918,7 +1930,7 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct WSAPROTOCOLCHAIN { + #[derive(Copy, Clone)] pub struct WSAPROTOCOLCHAIN { pub ChainLen: c_int, pub ChainEntries: [DWORD; MAX_PROTOCOL_CHAIN as usize], } @@ -1948,6 +1960,9 @@ pub mod types { pub dwProviderReserved: DWORD, pub szProtocol: [u8; WSAPROTOCOL_LEN as usize + 1], } + impl ::core::clone::Clone for WSAPROTOCOL_INFO { + fn clone(&self) -> WSAPROTOCOL_INFO { *self } + } pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; @@ -1966,6 +1981,9 @@ pub mod types { pub cFileName: [wchar_t; 260], // #define MAX_PATH 260 pub cAlternateFileName: [wchar_t; 14], } + impl ::core::clone::Clone for WIN32_FIND_DATAW { + fn clone(&self) -> WIN32_FIND_DATAW { *self } + } pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW; } @@ -1985,7 +2003,7 @@ pub mod types { pub type rlim_t = u64; #[repr(C)] - #[derive(Copy)] pub struct glob_t { + #[derive(Copy, Clone)] pub struct glob_t { pub gl_pathc: size_t, pub __unused1: c_int, pub gl_offs: size_t, @@ -2002,23 +2020,23 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct timeval { + #[derive(Copy, Clone)] pub struct timeval { pub tv_sec: time_t, pub tv_usec: suseconds_t, } #[repr(C)] - #[derive(Copy)] pub struct timespec { + #[derive(Copy, Clone)] pub struct timespec { pub tv_sec: time_t, pub tv_nsec: c_long, } - #[derive(Copy)] pub enum timezone {} + pub enum timezone {} pub type sighandler_t = size_t; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rlimit { pub rlim_cur: rlim_t, pub rlim_max: rlim_t, @@ -2029,7 +2047,7 @@ pub mod types { use types::os::common::posix01::timeval; use types::os::arch::c95::c_long; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct rusage { pub ru_utime: timeval, pub ru_stime: timeval, @@ -2059,7 +2077,7 @@ pub mod types { pub type in_port_t = u16; pub type in_addr_t = u32; #[repr(C)] - #[derive(Copy)] pub struct sockaddr { + #[derive(Copy, Clone)] pub struct sockaddr { pub sa_len: u8, pub sa_family: sa_family_t, pub sa_data: [u8; 14], @@ -2073,9 +2091,12 @@ pub mod types { pub __ss_align: i64, pub __ss_pad2: [u8; 112], } + impl ::core::clone::Clone for sockaddr_storage { + fn clone(&self) -> sockaddr_storage { *self } + } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in { + #[derive(Copy, Clone)] pub struct sockaddr_in { pub sin_len: u8, pub sin_family: sa_family_t, pub sin_port: in_port_t, @@ -2084,12 +2105,12 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct in_addr { + #[derive(Copy, Clone)] pub struct in_addr { pub s_addr: in_addr_t, } #[repr(C)] - #[derive(Copy)] pub struct sockaddr_in6 { + #[derive(Copy, Clone)] pub struct sockaddr_in6 { pub sin6_len: u8, pub sin6_family: sa_family_t, pub sin6_port: in_port_t, @@ -2099,24 +2120,24 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct in6_addr { + #[derive(Copy, Clone)] pub struct in6_addr { pub s6_addr: [u16; 8] } #[repr(C)] - #[derive(Copy)] pub struct ip_mreq { + #[derive(Copy, Clone)] pub struct ip_mreq { pub imr_multiaddr: in_addr, pub imr_interface: in_addr, } #[repr(C)] - #[derive(Copy)] pub struct ip6_mreq { + #[derive(Copy, Clone)] pub struct ip6_mreq { pub ipv6mr_multiaddr: in6_addr, pub ipv6mr_interface: c_uint, } #[repr(C)] - #[derive(Copy)] pub struct addrinfo { + #[derive(Copy, Clone)] pub struct addrinfo { pub ai_flags: c_int, pub ai_family: c_int, pub ai_socktype: c_int, @@ -2133,9 +2154,12 @@ pub mod types { pub sun_family: sa_family_t, pub sun_path: [c_char; 104] } + impl ::core::clone::Clone for sockaddr_un { + fn clone(&self) -> sockaddr_un { *self } + } #[repr(C)] - #[derive(Copy)] pub struct ifaddrs { + #[derive(Copy, Clone)] pub struct ifaddrs { pub ifa_next: *mut ifaddrs, pub ifa_name: *mut c_char, pub ifa_flags: c_uint, @@ -2200,7 +2224,7 @@ pub mod types { pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, pub st_nlink: nlink_t, @@ -2226,7 +2250,7 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -2236,6 +2260,9 @@ pub mod types { pub __sig: c_long, pub __opaque: [c_char; 36] } + impl ::core::clone::Clone for pthread_attr_t { + fn clone(&self) -> pthread_attr_t { *self } + } } pub mod posix08 { } @@ -2243,7 +2270,7 @@ pub mod types { } pub mod extra { #[repr(C)] - #[derive(Copy)] pub struct mach_timebase_info { + #[derive(Copy, Clone)] pub struct mach_timebase_info { pub numer: u32, pub denom: u32, } @@ -2306,7 +2333,7 @@ pub mod types { pub type blkcnt_t = i64; #[repr(C)] - #[derive(Copy)] pub struct stat { + #[derive(Copy, Clone)] pub struct stat { pub st_dev: dev_t, pub st_mode: mode_t, pub st_nlink: nlink_t, @@ -2332,7 +2359,7 @@ pub mod types { } #[repr(C)] - #[derive(Copy)] pub struct utimbuf { + #[derive(Copy, Clone)] pub struct utimbuf { pub actime: time_t, pub modtime: time_t, } @@ -2342,6 +2369,9 @@ pub mod types { pub __sig: c_long, pub __opaque: [c_char; 56] } + impl ::core::clone::Clone for pthread_attr_t { + fn clone(&self) -> pthread_attr_t { *self } + } } pub mod posix08 { } @@ -2349,7 +2379,7 @@ pub mod types { } pub mod extra { #[repr(C)] - #[derive(Copy)] pub struct mach_timebase_info { + #[derive(Copy, Clone)] pub struct mach_timebase_info { pub numer: u32, pub denom: u32, } @@ -2564,7 +2594,7 @@ pub mod consts { pub const ERROR_IO_PENDING: c_int = 997; pub const ERROR_FILE_INVALID : c_int = 1006; pub const ERROR_NOT_FOUND: c_int = 1168; - pub const INVALID_HANDLE_VALUE: HANDLE = -1 as HANDLE; + pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; pub const DELETE : DWORD = 0x00010000; pub const READ_CONTROL : DWORD = 0x00020000; @@ -2602,12 +2632,12 @@ pub mod consts { pub const WAIT_ABANDONED : DWORD = 0x00000080; pub const WAIT_OBJECT_0 : DWORD = 0x00000000; pub const WAIT_TIMEOUT : DWORD = 0x00000102; - pub const WAIT_FAILED : DWORD = -1; + pub const WAIT_FAILED : DWORD = !0; pub const DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001; pub const DUPLICATE_SAME_ACCESS : DWORD = 0x00000002; - pub const INFINITE : DWORD = -1; + pub const INFINITE : DWORD = !0; pub const STILL_ACTIVE : DWORD = 259; pub const MEM_COMMIT : DWORD = 0x00001000; diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 1cfac4d86680d..453d087196b13 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -239,7 +239,7 @@ pub trait Logger { struct DefaultLogger { handle: Stderr } /// Wraps the log level with fmt implementations. -#[derive(Copy, PartialEq, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)] pub struct LogLevel(pub u32); impl fmt::Display for LogLevel { @@ -355,7 +355,7 @@ pub struct LogRecord<'a> { } #[doc(hidden)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct LogLocation { pub module_path: &'static str, pub file: &'static str, diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs index 0c5f5cb0d444e..2ba3164e1b061 100644 --- a/src/librand/distributions/exponential.rs +++ b/src/librand/distributions/exponential.rs @@ -29,7 +29,7 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; /// Generate Normal Random /// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield /// College, Oxford -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Exp1(pub f64); // This could be done via `-rng.gen::().ln()` but that is slower. @@ -68,7 +68,7 @@ impl Rand for Exp1 { /// let v = exp.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a Exp(2) distribution", v); /// ``` -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Exp { /// `lambda` stored as `1/lambda`, since this is what we scale by. lambda_inverse: f64 diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs index 7cecc6ac611e2..fa41c3edfe5ac 100644 --- a/src/librand/distributions/normal.rs +++ b/src/librand/distributions/normal.rs @@ -28,7 +28,7 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; /// Generate Normal Random /// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield /// College, Oxford -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct StandardNormal(pub f64); impl Rand for StandardNormal { @@ -85,7 +85,7 @@ impl Rand for StandardNormal { /// let v = normal.ind_sample(&mut rand::thread_rng()); /// println!("{} is from a N(2, 9) distribution", v) /// ``` -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Normal { mean: f64, std_dev: f64, @@ -134,7 +134,7 @@ impl IndependentSample for Normal { /// let v = log_normal.ind_sample(&mut rand::thread_rng()); /// println!("{} is from an ln N(2, 9) distribution", v) /// ``` -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct LogNormal { norm: Normal } diff --git a/src/librand/reseeding.rs b/src/librand/reseeding.rs index ab4939f57d41a..98d1bbf5af9da 100644 --- a/src/librand/reseeding.rs +++ b/src/librand/reseeding.rs @@ -134,7 +134,7 @@ pub trait Reseeder { /// Reseed an RNG using a `Default` instance. This reseeds by /// replacing the RNG with the result of a `Default::default` call. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct ReseedWithDefault; impl Reseeder for ReseedWithDefault { diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs index 3e91b98877062..e2875ac8ca529 100644 --- a/src/librbml/lib.rs +++ b/src/librbml/lib.rs @@ -175,7 +175,7 @@ pub struct TaggedDoc<'a> { pub doc: Doc<'a>, } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum EbmlEncoderTag { // tags 00..1f are reserved for auto-serialization. // first NUM_IMPLICIT_TAGS tags are implicitly sized and lengths are not encoded. @@ -265,7 +265,7 @@ pub mod reader { ) } - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct Res { pub val: usize, pub next: usize diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index b3ad96c4b5f16..a4bb17bc35476 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -120,6 +120,8 @@ pub mod middle { pub mod traits; pub mod ty; pub mod ty_fold; + pub mod ty_match; + pub mod ty_relate; pub mod ty_walk; pub mod weak_lang_items; } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 9093cd00ca001..495044f945949 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -113,7 +113,7 @@ declare_lint! { } /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct HardwiredLints; impl LintPass for HardwiredLints { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 23f9cbc3a4b9c..498b2ce518c16 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -41,7 +41,7 @@ pub use lint::context::{Context, LintStore, raw_emit_lint, check_crate, gather_a GatherNodeLevels}; /// Specification of a single lint. -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Lint { /// A string identifier for the lint. /// diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index e4c0eda0448bd..cda0084768644 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -116,7 +116,7 @@ pub const tag_items_data_item_reexport_def_id: usize = 0x47; pub const tag_items_data_item_reexport_name: usize = 0x48; // used to encode crate_ctxt side tables -#[derive(Copy, PartialEq, FromPrimitive)] +#[derive(Copy, Clone, PartialEq, FromPrimitive)] #[repr(usize)] pub enum astencode_tag { // Reserves 0x50 -- 0x6f tag_ast = 0x50, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index ebc3a6fd52c93..d528e38d341cf 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -29,7 +29,7 @@ use syntax::parse::token; use std::collections::hash_map::HashMap; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct MethodInfo { pub name: ast::Name, pub def_id: ast::DefId, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a8f83bee7f682..862ced78c082c 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -34,8 +34,7 @@ use std::io::prelude::*; use std::io::{Cursor, SeekFrom}; use syntax::abi; use syntax::ast::{self, DefId, NodeId}; -use syntax::ast_map::{PathElem, PathElems}; -use syntax::ast_map; +use syntax::ast_map::{self, LinkedPath, PathElem, PathElems}; use syntax::ast_util::*; use syntax::ast_util; use syntax::attr; @@ -1513,7 +1512,7 @@ fn encode_info_for_items(ecx: &EncodeContext, &krate.module, &[], ast::CRATE_NODE_ID, - [].iter().cloned().chain(None), + [].iter().cloned().chain(LinkedPath::empty()), syntax::parse::token::special_idents::invalid, ast::Public); @@ -1874,7 +1873,7 @@ fn encode_misc_info(ecx: &EncodeContext, } // Encode reexports for the root module. - encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(None)); + encode_reexports(ecx, rbml_w, 0, [].iter().cloned().chain(LinkedPath::empty())); rbml_w.end_tag(); rbml_w.end_tag(); diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 284e76b328a69..1567f4b99475c 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -21,7 +21,7 @@ use std::path::{Path, PathBuf}; use util::fs as myfs; use session::search_paths::{SearchPaths, PathKind}; -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum FileMatch { FileMatches, FileDoesntMatch, diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index e2eebbfdc724d..3fb128b1881f5 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -43,7 +43,7 @@ use syntax::parse::token; // def-id will depend on where it originated from. Therefore, the conversion // function is given an indicator of the source of the def-id. See // astencode.rs for more information. -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum DefIdSource { // Identifies a struct, trait, enum, etc. NominalType, diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 24c54b53590c0..cbc2ef1535ea6 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -25,7 +25,7 @@ struct CFGBuilder<'a, 'tcx: 'a> { loop_scopes: Vec, } -#[derive(Copy)] +#[derive(Copy, Clone)] struct LoopScope { loop_id: ast::NodeId, // id of loop/while node continue_index: CFGIndex, // where to go on a `loop` diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs index e8a99f59b1e95..ad4fdcd7b834e 100644 --- a/src/librustc/middle/cfg/mod.rs +++ b/src/librustc/middle/cfg/mod.rs @@ -24,7 +24,7 @@ pub struct CFG { pub exit: CFGIndex, } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum CFGNodeData { AST(ast::NodeId), Entry, diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 497022ac6ac49..ce011f2561b79 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -76,7 +76,7 @@ bitflags! { } } -#[derive(Copy, Eq, PartialEq)] +#[derive(Copy, Clone, Eq, PartialEq)] enum Mode { Const, Static, diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index ea584407944ab..bf6829d967650 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -21,7 +21,7 @@ enum Context { Normal, Loop, Closure } -#[derive(Copy)] +#[derive(Copy, Clone)] struct CheckLoopVisitor<'a> { sess: &'a Session, cx: Context diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 01692158c17f4..79f4d62b45e75 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -128,7 +128,7 @@ enum Usefulness { NotUseful } -#[derive(Copy)] +#[derive(Copy, Clone)] enum WitnessPreference { ConstructWitness, LeaveOutWitness diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index a112ce6bd287c..f69ac03052092 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -28,7 +28,7 @@ use syntax::visit; use syntax::print::{pp, pprust}; use util::nodemap::NodeMap; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum EntryOrExit { Entry, Exit, @@ -108,7 +108,7 @@ impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O pprust::NodeIdent(_) | pprust::NodeName(_) => 0, pprust::NodeExpr(expr) => expr.id, pprust::NodeBlock(blk) => blk.id, - pprust::NodeItem(_) => 0, + pprust::NodeItem(_) | pprust::NodeSubItem(_) => 0, pprust::NodePat(pat) => pat.id }; diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index 1a054c0f464aa..6707a4d3fd775 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -65,7 +65,7 @@ pub enum Def { /// ::AssocX::AssocY::MethodOrAssocType /// ^~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~~~~~~~~~~~ /// base_def depth = 2 -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct PathResolution { pub base_def: Def, pub last_private: LastPrivate, @@ -85,6 +85,17 @@ impl PathResolution { pub fn def_id(&self) -> ast::DefId { self.full_def().def_id() } + + pub fn new(base_def: Def, + last_private: LastPrivate, + depth: usize) + -> PathResolution { + PathResolution { + base_def: base_def, + last_private: last_private, + depth: depth, + } + } } // Definition mapping @@ -93,7 +104,7 @@ pub type DefMap = RefCell>; // within. pub type ExportMap = NodeMap>; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Export { pub name: ast::Name, // The name of the target. pub def_id: ast::DefId, // The definition of the target. diff --git a/src/librustc/middle/effect.rs b/src/librustc/middle/effect.rs index 5d970c59f639b..814492cbef1dd 100644 --- a/src/librustc/middle/effect.rs +++ b/src/librustc/middle/effect.rs @@ -22,7 +22,7 @@ use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum UnsafeContext { SafeContext, UnsafeFn, diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index e98b438d370c7..2fa9c7c8fbebb 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -94,7 +94,7 @@ pub trait Delegate<'tcx> { mode: MutateMode); } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum LoanCause { ClosureCapture(Span), AddrOf, @@ -106,20 +106,20 @@ pub enum LoanCause { MatchDiscriminant } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum ConsumeMode { Copy, // reference to x where x has a type that copies Move(MoveReason), // reference to x where x has a type that moves } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum MoveReason { DirectRefMove, PatBindingMove, CaptureMove, } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum MatchMode { NonBindingMatch, BorrowingMatch, @@ -127,7 +127,7 @@ pub enum MatchMode { MovingMatch, } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] enum TrackMatchMode { Unknown, Definite(MatchMode), @@ -194,14 +194,14 @@ impl TrackMatchMode { } } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum MutateMode { Init, JustWrite, // x = y WriteAndRead, // x += y } -#[derive(Copy)] +#[derive(Copy, Clone)] enum OverloadedCallType { FnOverloadedCall, FnMutOverloadedCall, diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 8673273f9b3c9..a9ac61b49eca8 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -66,13 +66,13 @@ pub struct NodeIndex(pub usize); #[allow(non_upper_case_globals)] pub const InvalidNodeIndex: NodeIndex = NodeIndex(usize::MAX); -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct EdgeIndex(pub usize); #[allow(non_upper_case_globals)] pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(usize::MAX); // Use a private field here to guarantee no more instances are created: -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Direction { repr: usize } #[allow(non_upper_case_globals)] pub const Outgoing: Direction = Direction { repr: 0 }; diff --git a/src/librustc/middle/infer/bivariate.rs b/src/librustc/middle/infer/bivariate.rs index 17b0d788590c4..940dc75271c22 100644 --- a/src/librustc/middle/infer/bivariate.rs +++ b/src/librustc/middle/infer/bivariate.rs @@ -25,66 +25,54 @@ //! In particular, it might be enough to say (A,B) are bivariant for //! all (A,B). -use middle::ty::BuiltinBounds; +use super::combine::{self, CombineFields}; +use super::type_variable::{BiTo}; + use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::infer::combine::*; -use middle::infer::cres; -use middle::infer::type_variable::BiTo; -use util::ppaux::Repr; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use util::ppaux::{Repr}; -pub struct Bivariate<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Bivariate<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Bivariate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Bivariate<'f, 'tcx> { - Bivariate { fields: cf } +impl<'a, 'tcx> Bivariate<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Bivariate<'a, 'tcx> { + Bivariate { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { - fn tag(&self) -> String { "Bivariate".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Bivariate<'a, 'tcx> { + fn tag(&self) -> &'static str { "Bivariate" } - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> - { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Contravariant => self.tys(a, b), - ty::Bivariant => self.tys(a, b), - } - } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> - { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Contravariant => self.regions(a, b), - ty::Bivariant => self.regions(a, b), - } - } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn regions(&self, a: ty::Region, _: ty::Region) -> cres<'tcx, ty::Region> { - Ok(a) - } - - fn builtin_bounds(&self, - a: BuiltinBounds, - b: BuiltinBounds) - -> cres<'tcx, BuiltinBounds> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - if a != b { - Err(ty::terr_builtin_bounds(expected_found(self, a, b))) - } else { - Ok(a) + match variance { + // If we have Foo and Foo is invariant w/r/t A, + // and we want to assert that + // + // Foo <: Foo || + // Foo <: Foo + // + // then still A must equal B. + ty::Invariant => self.relate(a, b), + + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.relate(a, b), + ty::Contravariant => self.relate(a, b), } } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); if a == b { return Ok(a); } @@ -109,17 +97,22 @@ impl<'f, 'tcx> Combine<'tcx> for Bivariate<'f, 'tcx> { } _ => { - super_tys(self, a, b) + combine::super_combine_tys(self.fields.infcx, self, a, b) } } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> + fn regions(&mut self, a: ty::Region, _: ty::Region) -> RelateResult<'tcx, ty::Region> { + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> { let a1 = ty::erase_late_bound_regions(self.tcx(), a); let b1 = ty::erase_late_bound_regions(self.tcx(), b); - let c = try!(Combineable::combine(self, &a1, &b1)); + let c = try!(self.relate(&a1, &b1)); Ok(ty::Binder(c)) } } diff --git a/src/librustc/middle/infer/combine.rs b/src/librustc/middle/infer/combine.rs index 9aa17b2b1d9fe..86f12b669b35e 100644 --- a/src/librustc/middle/infer/combine.rs +++ b/src/librustc/middle/infer/combine.rs @@ -37,395 +37,21 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; -use super::{InferCtxt, cres}; +use super::{InferCtxt}; use super::{MiscVariable, TypeTrace}; use super::type_variable::{RelationDir, BiTo, EqTo, SubtypeOf, SupertypeOf}; -use middle::subst; -use middle::subst::{ErasedRegions, NonerasedRegions, Substs}; -use middle::ty::{FloatVar, FnSig, IntVar, TyVar}; +use middle::ty::{TyVar}; use middle::ty::{IntType, UintType}; -use middle::ty::BuiltinBounds; use middle::ty::{self, Ty}; use middle::ty_fold; use middle::ty_fold::{TypeFolder, TypeFoldable}; +use middle::ty_relate::{self, Relate, RelateResult, TypeRelation}; use util::ppaux::Repr; -use std::rc::Rc; -use syntax::ast::Unsafety; use syntax::ast; -use syntax::abi; use syntax::codemap::Span; -pub trait Combine<'tcx> : Sized { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { self.infcx().tcx } - fn tag(&self) -> String; - - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx>; - - fn infcx<'a>(&'a self) -> &'a InferCtxt<'a, 'tcx> { self.fields().infcx } - fn a_is_expected(&self) -> bool { self.fields().a_is_expected } - fn trace(&self) -> TypeTrace<'tcx> { self.fields().trace.clone() } - fn equate<'a>(&'a self) -> Equate<'a, 'tcx> { self.fields().equate() } - fn bivariate<'a>(&'a self) -> Bivariate<'a, 'tcx> { self.fields().bivariate() } - - fn sub<'a>(&'a self) -> Sub<'a, 'tcx> { self.fields().sub() } - fn lub<'a>(&'a self) -> Lub<'a, 'tcx> { Lub(self.fields().clone()) } - fn glb<'a>(&'a self) -> Glb<'a, 'tcx> { Glb(self.fields().clone()) } - - fn mts(&self, a: &ty::mt<'tcx>, b: &ty::mt<'tcx>) -> cres<'tcx, ty::mt<'tcx>> { - debug!("{}.mts({}, {})", - self.tag(), - a.repr(self.tcx()), - b.repr(self.tcx())); - - if a.mutbl != b.mutbl { - Err(ty::terr_mutability) - } else { - let mutbl = a.mutbl; - let variance = match mutbl { - ast::MutImmutable => ty::Covariant, - ast::MutMutable => ty::Invariant, - }; - let ty = try!(self.tys_with_variance(variance, a.ty, b.ty)); - Ok(ty::mt {ty: ty, mutbl: mutbl}) - } - } - - fn tys_with_variance(&self, variance: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>>; - - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>>; - - fn regions_with_variance(&self, variance: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region>; - - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region>; - - fn substs(&self, - item_def_id: ast::DefId, - a_subst: &subst::Substs<'tcx>, - b_subst: &subst::Substs<'tcx>) - -> cres<'tcx, subst::Substs<'tcx>> - { - debug!("substs: item_def_id={} a_subst={} b_subst={}", - item_def_id.repr(self.infcx().tcx), - a_subst.repr(self.infcx().tcx), - b_subst.repr(self.infcx().tcx)); - - let variances = if self.infcx().tcx.variance_computed.get() { - Some(ty::item_variances(self.infcx().tcx, item_def_id)) - } else { - None - }; - self.substs_variances(variances.as_ref().map(|v| &**v), a_subst, b_subst) - } - - fn substs_variances(&self, - variances: Option<&ty::ItemVariances>, - a_subst: &subst::Substs<'tcx>, - b_subst: &subst::Substs<'tcx>) - -> cres<'tcx, subst::Substs<'tcx>> - { - let mut substs = subst::Substs::empty(); - - for &space in &subst::ParamSpace::all() { - let a_tps = a_subst.types.get_slice(space); - let b_tps = b_subst.types.get_slice(space); - let t_variances = variances.map(|v| v.types.get_slice(space)); - let tps = try!(relate_type_params(self, t_variances, a_tps, b_tps)); - substs.types.replace(space, tps); - } - - match (&a_subst.regions, &b_subst.regions) { - (&ErasedRegions, _) | (_, &ErasedRegions) => { - substs.regions = ErasedRegions; - } - - (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => { - for &space in &subst::ParamSpace::all() { - let a_regions = a.get_slice(space); - let b_regions = b.get_slice(space); - let r_variances = variances.map(|v| v.regions.get_slice(space)); - let regions = try!(relate_region_params(self, - r_variances, - a_regions, - b_regions)); - substs.mut_regions().replace(space, regions); - } - } - } - - return Ok(substs); - - fn relate_type_params<'tcx, C: Combine<'tcx>>(this: &C, - variances: Option<&[ty::Variance]>, - a_tys: &[Ty<'tcx>], - b_tys: &[Ty<'tcx>]) - -> cres<'tcx, Vec>> - { - if a_tys.len() != b_tys.len() { - return Err(ty::terr_ty_param_size(expected_found(this, - a_tys.len(), - b_tys.len()))); - } - - (0.. a_tys.len()).map(|i| { - let a_ty = a_tys[i]; - let b_ty = b_tys[i]; - let v = variances.map_or(ty::Invariant, |v| v[i]); - this.tys_with_variance(v, a_ty, b_ty) - }).collect() - } - - fn relate_region_params<'tcx, C: Combine<'tcx>>(this: &C, - variances: Option<&[ty::Variance]>, - a_rs: &[ty::Region], - b_rs: &[ty::Region]) - -> cres<'tcx, Vec> - { - let tcx = this.infcx().tcx; - let num_region_params = a_rs.len(); - - debug!("relate_region_params(\ - a_rs={}, \ - b_rs={}, - variances={})", - a_rs.repr(tcx), - b_rs.repr(tcx), - variances.repr(tcx)); - - assert_eq!(num_region_params, - variances.map_or(num_region_params, - |v| v.len())); - - assert_eq!(num_region_params, b_rs.len()); - - (0..a_rs.len()).map(|i| { - let a_r = a_rs[i]; - let b_r = b_rs[i]; - let variance = variances.map_or(ty::Invariant, |v| v[i]); - this.regions_with_variance(variance, a_r, b_r) - }).collect() - } - } - - fn bare_fn_tys(&self, a: &ty::BareFnTy<'tcx>, - b: &ty::BareFnTy<'tcx>) -> cres<'tcx, ty::BareFnTy<'tcx>> { - let unsafety = try!(self.unsafeties(a.unsafety, b.unsafety)); - let abi = try!(self.abi(a.abi, b.abi)); - let sig = try!(self.binders(&a.sig, &b.sig)); - Ok(ty::BareFnTy {unsafety: unsafety, - abi: abi, - sig: sig}) - } - - fn fn_sigs(&self, a: &ty::FnSig<'tcx>, b: &ty::FnSig<'tcx>) -> cres<'tcx, ty::FnSig<'tcx>> { - if a.variadic != b.variadic { - return Err(ty::terr_variadic_mismatch(expected_found(self, a.variadic, b.variadic))); - } - - let inputs = try!(argvecs(self, - &a.inputs, - &b.inputs)); - - let output = try!(match (a.output, b.output) { - (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => - Ok(ty::FnConverging(try!(self.tys(a_ty, b_ty)))), - (ty::FnDiverging, ty::FnDiverging) => - Ok(ty::FnDiverging), - (a, b) => - Err(ty::terr_convergence_mismatch( - expected_found(self, a != ty::FnDiverging, b != ty::FnDiverging))), - }); - - return Ok(ty::FnSig {inputs: inputs, - output: output, - variadic: a.variadic}); - - - fn argvecs<'tcx, C>(combiner: &C, - a_args: &[Ty<'tcx>], - b_args: &[Ty<'tcx>]) - -> cres<'tcx, Vec>> - where C: Combine<'tcx> { - if a_args.len() == b_args.len() { - a_args.iter().zip(b_args.iter()) - .map(|(a, b)| combiner.args(*a, *b)).collect() - } else { - Err(ty::terr_arg_count) - } - } - } - - fn args(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - self.tys_with_variance(ty::Contravariant, a, b).and_then(|t| Ok(t)) - } - - fn unsafeties(&self, a: Unsafety, b: Unsafety) -> cres<'tcx, Unsafety> { - if a != b { - Err(ty::terr_unsafety_mismatch(expected_found(self, a, b))) - } else { - Ok(a) - } - } - - fn abi(&self, a: abi::Abi, b: abi::Abi) -> cres<'tcx, abi::Abi> { - if a == b { - Ok(a) - } else { - Err(ty::terr_abi_mismatch(expected_found(self, a, b))) - } - } - - fn projection_tys(&self, - a: &ty::ProjectionTy<'tcx>, - b: &ty::ProjectionTy<'tcx>) - -> cres<'tcx, ty::ProjectionTy<'tcx>> - { - if a.item_name != b.item_name { - Err(ty::terr_projection_name_mismatched( - expected_found(self, a.item_name, b.item_name))) - } else { - let trait_ref = try!(self.trait_refs(&*a.trait_ref, &*b.trait_ref)); - Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name }) - } - } - - fn projection_predicates(&self, - a: &ty::ProjectionPredicate<'tcx>, - b: &ty::ProjectionPredicate<'tcx>) - -> cres<'tcx, ty::ProjectionPredicate<'tcx>> - { - let projection_ty = try!(self.projection_tys(&a.projection_ty, &b.projection_ty)); - let ty = try!(self.tys(a.ty, b.ty)); - Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) - } - - fn projection_bounds(&self, - a: &Vec>, - b: &Vec>) - -> cres<'tcx, Vec>> - { - // To be compatible, `a` and `b` must be for precisely the - // same set of traits and item names. We always require that - // projection bounds lists are sorted by trait-def-id and item-name, - // so we can just iterate through the lists pairwise, so long as they are the - // same length. - if a.len() != b.len() { - Err(ty::terr_projection_bounds_length(expected_found(self, a.len(), b.len()))) - } else { - a.iter() - .zip(b.iter()) - .map(|(a, b)| self.binders(a, b)) - .collect() - } - } - - fn existential_bounds(&self, - a: &ty::ExistentialBounds<'tcx>, - b: &ty::ExistentialBounds<'tcx>) - -> cres<'tcx, ty::ExistentialBounds<'tcx>> - { - let r = try!(self.regions_with_variance(ty::Contravariant, a.region_bound, b.region_bound)); - let nb = try!(self.builtin_bounds(a.builtin_bounds, b.builtin_bounds)); - let pb = try!(self.projection_bounds(&a.projection_bounds, &b.projection_bounds)); - Ok(ty::ExistentialBounds { region_bound: r, - builtin_bounds: nb, - projection_bounds: pb }) - } - - fn builtin_bounds(&self, - a: BuiltinBounds, - b: BuiltinBounds) - -> cres<'tcx, BuiltinBounds> - { - // Two sets of builtin bounds are only relatable if they are - // precisely the same (but see the coercion code). - if a != b { - Err(ty::terr_builtin_bounds(expected_found(self, a, b))) - } else { - Ok(a) - } - } - - fn trait_refs(&self, - a: &ty::TraitRef<'tcx>, - b: &ty::TraitRef<'tcx>) - -> cres<'tcx, ty::TraitRef<'tcx>> - { - // Different traits cannot be related - if a.def_id != b.def_id { - Err(ty::terr_traits(expected_found(self, a.def_id, b.def_id))) - } else { - let substs = try!(self.substs(a.def_id, a.substs, b.substs)); - Ok(ty::TraitRef { def_id: a.def_id, substs: self.tcx().mk_substs(substs) }) - } - } - - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx>; - // this must be overridden to do correctly, so as to account for higher-ranked - // behavior -} - -pub trait Combineable<'tcx> : Repr<'tcx> + TypeFoldable<'tcx> { - fn combine>(combiner: &C, a: &Self, b: &Self) -> cres<'tcx, Self>; -} - -impl<'tcx,T> Combineable<'tcx> for Rc - where T : Combineable<'tcx> -{ - fn combine(combiner: &C, - a: &Rc, - b: &Rc) - -> cres<'tcx, Rc> - where C: Combine<'tcx> { - Ok(Rc::new(try!(Combineable::combine(combiner, &**a, &**b)))) - } -} - -impl<'tcx> Combineable<'tcx> for ty::TraitRef<'tcx> { - fn combine(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(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(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(combiner: &C, - a: &ty::FnSig<'tcx>, - b: &ty::FnSig<'tcx>) - -> cres<'tcx, ty::FnSig<'tcx>> - where C: Combine<'tcx> { - combiner.fn_sigs(a, b) - } -} - #[derive(Clone)] pub struct CombineFields<'a, 'tcx: 'a> { pub infcx: &'a InferCtxt<'a, 'tcx>, @@ -433,234 +59,133 @@ pub struct CombineFields<'a, 'tcx: 'a> { pub trace: TypeTrace<'tcx>, } -pub fn expected_found<'tcx, C, T>(this: &C, - a: T, - b: T) - -> ty::expected_found - where C: Combine<'tcx> { - if this.a_is_expected() { - ty::expected_found {expected: a, found: b} - } else { - ty::expected_found {expected: b, found: a} - } -} - -pub fn super_tys<'tcx, C>(this: &C, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - let tcx = this.infcx().tcx; - let a_sty = &a.sty; - let b_sty = &b.sty; - debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); - return match (a_sty, b_sty) { - // The "subtype" ought to be handling cases involving var: - (&ty::ty_infer(TyVar(_)), _) - | (_, &ty::ty_infer(TyVar(_))) => - tcx.sess.bug( - &format!("{}: bot and var types should have been handled ({},{})", - this.tag(), - a.repr(this.infcx().tcx), - b.repr(this.infcx().tcx))), - - (&ty::ty_err, _) | (_, &ty::ty_err) => Ok(tcx.types.err), +pub fn super_combine_tys<'a,'tcx:'a,R>(infcx: &InferCtxt<'a, 'tcx>, + relation: &mut R, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let a_is_expected = relation.a_is_expected(); + match (&a.sty, &b.sty) { // Relate integral variables to other types - (&ty::ty_infer(IntVar(a_id)), &ty::ty_infer(IntVar(b_id))) => { - try!(this.infcx().simple_vars(this.a_is_expected(), - a_id, b_id)); + (&ty::ty_infer(ty::IntVar(a_id)), &ty::ty_infer(ty::IntVar(b_id))) => { + try!(infcx.int_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| int_unification_error(a_is_expected, e))); Ok(a) } - (&ty::ty_infer(IntVar(v_id)), &ty::ty_int(v)) => { - unify_integral_variable(this, this.a_is_expected(), - v_id, IntType(v)) + (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_int(v)) => { + unify_integral_variable(infcx, a_is_expected, v_id, IntType(v)) } - (&ty::ty_int(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), - v_id, IntType(v)) + (&ty::ty_int(v), &ty::ty_infer(ty::IntVar(v_id))) => { + unify_integral_variable(infcx, !a_is_expected, v_id, IntType(v)) } - (&ty::ty_infer(IntVar(v_id)), &ty::ty_uint(v)) => { - unify_integral_variable(this, this.a_is_expected(), - v_id, UintType(v)) + (&ty::ty_infer(ty::IntVar(v_id)), &ty::ty_uint(v)) => { + unify_integral_variable(infcx, a_is_expected, v_id, UintType(v)) } - (&ty::ty_uint(v), &ty::ty_infer(IntVar(v_id))) => { - unify_integral_variable(this, !this.a_is_expected(), - v_id, UintType(v)) + (&ty::ty_uint(v), &ty::ty_infer(ty::IntVar(v_id))) => { + unify_integral_variable(infcx, !a_is_expected, v_id, UintType(v)) } // Relate floating-point variables to other types - (&ty::ty_infer(FloatVar(a_id)), &ty::ty_infer(FloatVar(b_id))) => { - try!(this.infcx().simple_vars(this.a_is_expected(), a_id, b_id)); + (&ty::ty_infer(ty::FloatVar(a_id)), &ty::ty_infer(ty::FloatVar(b_id))) => { + try!(infcx.float_unification_table + .borrow_mut() + .unify_var_var(a_id, b_id) + .map_err(|e| float_unification_error(relation.a_is_expected(), e))); Ok(a) } - (&ty::ty_infer(FloatVar(v_id)), &ty::ty_float(v)) => { - unify_float_variable(this, this.a_is_expected(), v_id, v) - } - (&ty::ty_float(v), &ty::ty_infer(FloatVar(v_id))) => { - unify_float_variable(this, !this.a_is_expected(), v_id, v) + (&ty::ty_infer(ty::FloatVar(v_id)), &ty::ty_float(v)) => { + unify_float_variable(infcx, a_is_expected, v_id, v) } - - (&ty::ty_char, _) - | (&ty::ty_bool, _) - | (&ty::ty_int(_), _) - | (&ty::ty_uint(_), _) - | (&ty::ty_float(_), _) => { - if a == b { - Ok(a) - } else { - Err(ty::terr_sorts(expected_found(this, a, b))) - } + (&ty::ty_float(v), &ty::ty_infer(ty::FloatVar(v_id))) => { + unify_float_variable(infcx, !a_is_expected, v_id, v) } - (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) if - a_p.idx == b_p.idx && a_p.space == b_p.space => Ok(a), - - (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs)) - if a_id == b_id => { - let substs = try!(this.substs(a_id, a_substs, b_substs)); - Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs))) + // All other cases of inference are errors + (&ty::ty_infer(_), _) | + (_, &ty::ty_infer(_)) => { + Err(ty::terr_sorts(ty_relate::expected_found(relation, &a, &b))) } - (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => { - debug!("Trying to match traits {:?} and {:?}", a, b); - let principal = try!(this.binders(&a_.principal, &b_.principal)); - let bounds = try!(this.existential_bounds(&a_.bounds, &b_.bounds)); - Ok(ty::mk_trait(tcx, principal, bounds)) - } - - (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs)) - if a_id == b_id => { - let substs = try!(this.substs(a_id, a_substs, b_substs)); - Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) - } - - (&ty::ty_closure(a_id, a_substs), - &ty::ty_closure(b_id, b_substs)) - if a_id == b_id => { - // All ty_closure types with the same id represent - // the (anonymous) type of the same closure expression. So - // all of their regions should be equated. - let substs = try!(this.substs_variances(None, a_substs, b_substs)); - Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs))) - } - (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => { - let typ = try!(this.tys(a_inner, b_inner)); - Ok(ty::mk_uniq(tcx, typ)) - } - - (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => { - let mt = try!(this.mts(a_mt, b_mt)); - Ok(ty::mk_ptr(tcx, mt)) - } - - (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => { - let r = try!(this.regions_with_variance(ty::Contravariant, *a_r, *b_r)); - let mt = try!(this.mts(a_mt, b_mt)); - Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt)) - } - - (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => { - this.tys(a_t, b_t).and_then(|t| { - if sz_a == sz_b { - Ok(ty::mk_vec(tcx, t, Some(sz_a))) - } else { - Err(ty::terr_fixed_array_size(expected_found(this, sz_a, sz_b))) - } - }) - } - - (&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => { - this.tys(a_t, b_t).and_then(|t| { - if sz_a == sz_b { - Ok(ty::mk_vec(tcx, t, sz_a)) - } else { - Err(ty::terr_sorts(expected_found(this, a, b))) - } - }) - } - - (&ty::ty_str, &ty::ty_str) => Ok(ty::mk_str(tcx)), - - (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => { - if as_.len() == bs.len() { - as_.iter().zip(bs.iter()) - .map(|(a, b)| this.tys(*a, *b)) - .collect::>() - .map(|ts| ty::mk_tup(tcx, ts)) - } else if as_.len() != 0 && bs.len() != 0 { - Err(ty::terr_tuple_size( - expected_found(this, as_.len(), bs.len()))) - } else { - Err(ty::terr_sorts(expected_found(this, a, b))) - } - } - - (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty)) - if a_opt_def_id == b_opt_def_id => - { - let fty = try!(this.bare_fn_tys(a_fty, b_fty)); - Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty))) - } - - (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => { - let projection_ty = try!(this.projection_tys(a_data, b_data)); - Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) - } - - _ => Err(ty::terr_sorts(expected_found(this, a, b))), - }; - - fn unify_integral_variable<'tcx, C>(this: &C, - vid_is_expected: bool, - vid: ty::IntVid, - val: ty::IntVarValue) - -> cres<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); - match val { - IntType(v) => Ok(ty::mk_mach_int(this.tcx(), v)), - UintType(v) => Ok(ty::mk_mach_uint(this.tcx(), v)), + _ => { + ty_relate::super_relate_tys(relation, a, b) } } +} - fn unify_float_variable<'tcx, C>(this: &C, - vid_is_expected: bool, - vid: ty::FloatVid, - val: ast::FloatTy) - -> cres<'tcx, Ty<'tcx>> - where C: Combine<'tcx> { - try!(this.infcx().simple_var_t(vid_is_expected, vid, val)); - Ok(ty::mk_mach_float(this.tcx(), val)) +fn unify_integral_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + vid_is_expected: bool, + vid: ty::IntVid, + val: ty::IntVarValue) + -> RelateResult<'tcx, Ty<'tcx>> +{ + try!(infcx + .int_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| int_unification_error(vid_is_expected, e))); + match val { + IntType(v) => Ok(ty::mk_mach_int(infcx.tcx, v)), + UintType(v) => Ok(ty::mk_mach_uint(infcx.tcx, v)), } } -impl<'f, 'tcx> CombineFields<'f, 'tcx> { - pub fn switch_expected(&self) -> CombineFields<'f, 'tcx> { +fn unify_float_variable<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>, + vid_is_expected: bool, + vid: ty::FloatVid, + val: ast::FloatTy) + -> RelateResult<'tcx, Ty<'tcx>> +{ + try!(infcx + .float_unification_table + .borrow_mut() + .unify_var_value(vid, val) + .map_err(|e| float_unification_error(vid_is_expected, e))); + Ok(ty::mk_mach_float(infcx.tcx, val)) +} + +impl<'a, 'tcx> CombineFields<'a, 'tcx> { + pub fn tcx(&self) -> &'a ty::ctxt<'tcx> { + self.infcx.tcx + } + + pub fn switch_expected(&self) -> CombineFields<'a, 'tcx> { CombineFields { a_is_expected: !self.a_is_expected, ..(*self).clone() } } - fn equate(&self) -> Equate<'f, 'tcx> { - Equate((*self).clone()) + pub fn equate(&self) -> Equate<'a, 'tcx> { + Equate::new(self.clone()) + } + + pub fn bivariate(&self) -> Bivariate<'a, 'tcx> { + Bivariate::new(self.clone()) + } + + pub fn sub(&self) -> Sub<'a, 'tcx> { + Sub::new(self.clone()) } - fn bivariate(&self) -> Bivariate<'f, 'tcx> { - Bivariate((*self).clone()) + pub fn lub(&self) -> Lub<'a, 'tcx> { + Lub::new(self.clone()) } - fn sub(&self) -> Sub<'f, 'tcx> { - Sub((*self).clone()) + pub fn glb(&self) -> Glb<'a, 'tcx> { + Glb::new(self.clone()) } pub fn instantiate(&self, a_ty: Ty<'tcx>, dir: RelationDir, b_vid: ty::TyVid) - -> cres<'tcx, ()> + -> RelateResult<'tcx, ()> { let tcx = self.infcx.tcx; let mut stack = Vec::new(); @@ -724,15 +249,12 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { // relations wind up attributed to the same spans. We need // to associate causes/spans with each of the relations in // the stack to get this right. - match dir { - BiTo => try!(self.bivariate().tys(a_ty, b_ty)), - - EqTo => try!(self.equate().tys(a_ty, b_ty)), - - SubtypeOf => try!(self.sub().tys(a_ty, b_ty)), - - SupertypeOf => try!(self.sub().tys_with_variance(ty::Contravariant, a_ty, b_ty)), - }; + try!(match dir { + BiTo => self.bivariate().relate(&a_ty, &b_ty), + EqTo => self.equate().relate(&a_ty, &b_ty), + SubtypeOf => self.sub().relate(&a_ty, &b_ty), + SupertypeOf => self.sub().relate_with_variance(ty::Contravariant, &a_ty, &b_ty), + }); } Ok(()) @@ -746,7 +268,7 @@ impl<'f, 'tcx> CombineFields<'f, 'tcx> { ty: Ty<'tcx>, for_vid: ty::TyVid, make_region_vars: bool) - -> cres<'tcx, Ty<'tcx>> + -> RelateResult<'tcx, Ty<'tcx>> { let mut generalize = Generalizer { infcx: self.infcx, @@ -839,3 +361,37 @@ impl<'cx, 'tcx> ty_fold::TypeFolder<'tcx> for Generalizer<'cx, 'tcx> { self.infcx.next_region_var(MiscVariable(self.span)) } } + +pub trait RelateResultCompare<'tcx, T> { + fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where + F: FnOnce() -> ty::type_err<'tcx>; +} + +impl<'tcx, T:Clone + PartialEq> RelateResultCompare<'tcx, T> for RelateResult<'tcx, T> { + fn compare(&self, t: T, f: F) -> RelateResult<'tcx, T> where + F: FnOnce() -> ty::type_err<'tcx>, + { + self.clone().and_then(|s| { + if s == t { + self.clone() + } else { + Err(f()) + } + }) + } +} + +fn int_unification_error<'tcx>(a_is_expected: bool, v: (ty::IntVarValue, ty::IntVarValue)) + -> ty::type_err<'tcx> +{ + let (a, b) = v; + ty::terr_int_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b)) +} + +fn float_unification_error<'tcx>(a_is_expected: bool, + v: (ast::FloatTy, ast::FloatTy)) + -> ty::type_err<'tcx> +{ + let (a, b) = v; + ty::terr_float_mismatch(ty_relate::expected_found_bool(a_is_expected, &a, &b)) +} diff --git a/src/librustc/middle/infer/equate.rs b/src/librustc/middle/infer/equate.rs index 59ed2dfd24f25..2003f459d89b4 100644 --- a/src/librustc/middle/infer/equate.rs +++ b/src/librustc/middle/infer/equate.rs @@ -8,51 +8,43 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::combine::{self, CombineFields}; +use super::higher_ranked::HigherRankedRelations; +use super::{Subtype}; +use super::type_variable::{EqTo}; + use middle::ty::{self, Ty}; use middle::ty::TyVar; -use middle::infer::combine::*; -use middle::infer::cres; -use middle::infer::Subtype; -use middle::infer::type_variable::EqTo; -use util::ppaux::Repr; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use util::ppaux::{Repr}; -pub struct Equate<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Equate<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Equate<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Equate<'f, 'tcx> { - Equate { fields: cf } +impl<'a, 'tcx> Equate<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Equate<'a, 'tcx> { + Equate { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { - fn tag(&self) -> String { "Equate".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a,'tcx> for Equate<'a, 'tcx> { + fn tag(&self) -> &'static str { "Equate" } - fn tys_with_variance(&self, _: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> - { - // Once we're equating, it doesn't matter what the variance is. - self.tys(a, b) - } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } - fn regions_with_variance(&self, _: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> - { - // Once we're equating, it doesn't matter what the variance is. - self.regions(a, b) - } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { - debug!("{}.regions({}, {})", - self.tag(), - a.repr(self.fields.infcx.tcx), - b.repr(self.fields.infcx.tcx)); - self.infcx().region_vars.make_eqregion(Subtype(self.trace()), a, b); - Ok(a) + fn relate_with_variance>(&mut self, + _: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + self.relate(a, b) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { debug!("{}.tys({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); if a == b { return Ok(a); } @@ -77,15 +69,26 @@ impl<'f, 'tcx> Combine<'tcx> for Equate<'f, 'tcx> { } _ => { - super_tys(self, a, b) + combine::super_combine_tys(self.fields.infcx, self, a, b) } } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({}, {})", + self.tag(), + a.repr(self.fields.infcx.tcx), + b.repr(self.fields.infcx.tcx)); + let origin = Subtype(self.fields.trace.clone()); + self.fields.infcx.region_vars.make_eqregion(origin, a, b); + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> { - try!(self.sub().binders(a, b)); - self.sub().binders(b, a) + try!(self.fields.higher_ranked_sub(a, b)); + self.fields.higher_ranked_sub(b, a) } } diff --git a/src/librustc/middle/infer/freshen.rs b/src/librustc/middle/infer/freshen.rs index e41b949d5df1d..29f74d12ea3e8 100644 --- a/src/librustc/middle/infer/freshen.rs +++ b/src/librustc/middle/infer/freshen.rs @@ -37,7 +37,7 @@ use middle::ty_fold::TypeFolder; use std::collections::hash_map::{self, Entry}; use super::InferCtxt; -use super::unify::InferCtxtMethodsForSimplyUnifiableTypes; +use super::unify::ToType; pub struct TypeFreshener<'a, 'tcx:'a> { infcx: &'a InferCtxt<'a, 'tcx>, @@ -104,29 +104,38 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + let tcx = self.infcx.tcx; + match t.sty { ty::ty_infer(ty::TyVar(v)) => { - self.freshen(self.infcx.type_variables.borrow().probe(v), - ty::TyVar(v), - ty::FreshTy) + self.freshen( + self.infcx.type_variables.borrow().probe(v), + ty::TyVar(v), + ty::FreshTy) } ty::ty_infer(ty::IntVar(v)) => { - self.freshen(self.infcx.probe_var(v), - ty::IntVar(v), - ty::FreshIntTy) + self.freshen( + self.infcx.int_unification_table.borrow_mut() + .probe(v) + .map(|v| v.to_type(tcx)), + ty::IntVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FloatVar(v)) => { - self.freshen(self.infcx.probe_var(v), - ty::FloatVar(v), - ty::FreshIntTy) + self.freshen( + self.infcx.float_unification_table.borrow_mut() + .probe(v) + .map(|v| v.to_type(tcx)), + ty::FloatVar(v), + ty::FreshIntTy) } ty::ty_infer(ty::FreshTy(c)) | ty::ty_infer(ty::FreshIntTy(c)) => { if c >= self.freshen_count { - self.tcx().sess.bug( + tcx.sess.bug( &format!("Encountered a freshend type with id {} \ but our counter is only at {}", c, diff --git a/src/librustc/middle/infer/glb.rs b/src/librustc/middle/infer/glb.rs index 3b83d37f58234..5822fb0f2d432 100644 --- a/src/librustc/middle/infer/glb.rs +++ b/src/librustc/middle/infer/glb.rs @@ -8,67 +8,79 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::*; -use super::lattice::*; +use super::combine::CombineFields; use super::higher_ranked::HigherRankedRelations; -use super::cres; +use super::InferCtxt; +use super::lattice::{self, LatticeDir}; use super::Subtype; use middle::ty::{self, Ty}; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use util::ppaux::Repr; /// "Greatest lower bound" (common subtype) -pub struct Glb<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Glb<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Glb<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Glb<'f, 'tcx> { - Glb { fields: cf } +impl<'a, 'tcx> Glb<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Glb<'a, 'tcx> { + Glb { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Glb<'f, 'tcx> { - fn tag(&self) -> String { "Glb".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Glb<'a, 'tcx> { + fn tag(&self) -> &'static str { "Glb" } + + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Bivariant => self.bivariate().tys(a, b), - ty::Contravariant => self.lub().tys(a, b), + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.lub().relate(a, b), } } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> - { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Bivariant => self.bivariate().regions(a, b), - ty::Contravariant => self.lub().regions(a, b), - } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + lattice::super_lattice_tys(self, a, b) } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.fields.infcx.tcx), b.repr(self.fields.infcx.tcx)); - Ok(self.fields.infcx.region_vars.glb_regions(Subtype(self.trace()), a, b)) + let origin = Subtype(self.fields.trace.clone()); + Ok(self.fields.infcx.region_vars.glb_regions(origin, a, b)) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - super_lattice_tys(self, a, b) + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_glb(a, b) } +} - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> - { - self.higher_ranked_glb(a, b) +impl<'a, 'tcx> LatticeDir<'a,'tcx> for Glb<'a, 'tcx> { + fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { + self.fields.infcx + } + + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + try!(sub.relate(&v, &a)); + try!(sub.relate(&v, &b)); + Ok(()) } } diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs index 16b387330b9ef..f347d28b93c2b 100644 --- a/src/librustc/middle/infer/higher_ranked/mod.rs +++ b/src/librustc/middle/infer/higher_ranked/mod.rs @@ -11,25 +11,26 @@ //! Helper routines for higher-ranked things. See the `doc` module at //! the end of the file for details. -use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap}; -use super::combine::{Combine, Combineable}; +use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap}; +use super::combine::CombineFields; use middle::subst; use middle::ty::{self, Binder}; use middle::ty_fold::{self, TypeFoldable}; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use syntax::codemap::Span; use util::nodemap::{FnvHashMap, FnvHashSet}; use util::ppaux::Repr; -pub trait HigherRankedRelations<'tcx> { - fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx>; +pub trait HigherRankedRelations<'a,'tcx> { + fn higher_ranked_sub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx>; + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx>; + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx>; } trait InferCtxtExt { @@ -40,15 +41,15 @@ trait InferCtxtExt { -> Vec; } -impl<'tcx,C> HigherRankedRelations<'tcx> for C - where C : Combine<'tcx> -{ +impl<'a,'tcx> HigherRankedRelations<'a,'tcx> for CombineFields<'a,'tcx> { fn higher_ranked_sub(&self, a: &Binder, b: &Binder) - -> cres<'tcx, Binder> - where T : Combineable<'tcx> + -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> { + let tcx = self.infcx.tcx; + debug!("higher_ranked_sub(a={}, b={})", - a.repr(self.tcx()), b.repr(self.tcx())); + a.repr(tcx), b.repr(tcx)); // Rather than checking the subtype relationship between `a` and `b` // as-is, we need to do some extra work here in order to make sure @@ -60,32 +61,32 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().try(|snapshot| { + return self.infcx.commit_if_ok(|snapshot| { // First, we instantiate each bound region in the subtype with a fresh // region variable. let (a_prime, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, a); // Second, we instantiate each bound region in the supertype with a // fresh concrete region. let (b_prime, skol_map) = - self.infcx().skolemize_late_bound_regions(b, snapshot); + self.infcx.skolemize_late_bound_regions(b, snapshot); - debug!("a_prime={}", a_prime.repr(self.tcx())); - debug!("b_prime={}", b_prime.repr(self.tcx())); + debug!("a_prime={}", a_prime.repr(tcx)); + debug!("b_prime={}", b_prime.repr(tcx)); // Compare types now that bound regions have been replaced. - let result = try!(Combineable::combine(self, &a_prime, &b_prime)); + let result = try!(self.sub().relate(&a_prime, &b_prime)); // Presuming type comparison succeeds, we need to check // that the skolemized regions do not "leak". - match leak_check(self.infcx(), &skol_map, snapshot) { + match leak_check(self.infcx, &skol_map, snapshot) { Ok(()) => { } Err((skol_br, tainted_region)) => { - if self.a_is_expected() { + if self.a_is_expected { debug!("Not as polymorphic!"); return Err(ty::terr_regions_insufficiently_polymorphic(skol_br, tainted_region)); @@ -98,42 +99,42 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } debug!("higher_ranked_sub: OK result={}", - result.repr(self.tcx())); + result.repr(tcx)); Ok(ty::Binder(result)) }); } - fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx> + fn higher_ranked_lub(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> { // Start a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().try(|snapshot| { + return self.infcx.commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. - let span = self.trace().origin.span(); + let span = self.trace.origin.span(); let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( + self.infcx.replace_late_bound_regions_with_fresh_var( span, HigherRankedType, a); let (b_with_fresh, _) = - self.infcx().replace_late_bound_regions_with_fresh_var( + self.infcx.replace_late_bound_regions_with_fresh_var( span, HigherRankedType, b); // Collect constraints. let result0 = - try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + try!(self.lub().relate(&a_with_fresh, &b_with_fresh)); let result0 = - self.infcx().resolve_type_vars_if_possible(&result0); + self.infcx.resolve_type_vars_if_possible(&result0); debug!("lub result0 = {}", result0.repr(self.tcx())); // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); - let span = self.trace().origin.span(); + let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); + let span = self.trace.origin.span(); let result1 = fold_regions_in( self.tcx(), &result0, - |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, &new_vars, &a_map, r)); debug!("lub({},{}) = {}", @@ -194,40 +195,40 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } - fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> cres<'tcx, Binder> - where T : Combineable<'tcx> + fn higher_ranked_glb(&self, a: &Binder, b: &Binder) -> RelateResult<'tcx, Binder> + where T: Relate<'a,'tcx> { - debug!("{}.higher_ranked_glb({}, {})", - self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); + debug!("higher_ranked_glb({}, {})", + a.repr(self.tcx()), b.repr(self.tcx())); // Make a snapshot so we can examine "all bindings that were // created as part of this type comparison". - return self.infcx().try(|snapshot| { + return self.infcx.commit_if_ok(|snapshot| { // Instantiate each bound region with a fresh region variable. let (a_with_fresh, a_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, a); + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, a); let (b_with_fresh, b_map) = - self.infcx().replace_late_bound_regions_with_fresh_var( - self.trace().origin.span(), HigherRankedType, b); + self.infcx.replace_late_bound_regions_with_fresh_var( + self.trace.origin.span(), HigherRankedType, b); let a_vars = var_ids(self, &a_map); let b_vars = var_ids(self, &b_map); // Collect constraints. let result0 = - try!(Combineable::combine(self, &a_with_fresh, &b_with_fresh)); + try!(self.glb().relate(&a_with_fresh, &b_with_fresh)); let result0 = - self.infcx().resolve_type_vars_if_possible(&result0); + self.infcx.resolve_type_vars_if_possible(&result0); debug!("glb result0 = {}", result0.repr(self.tcx())); // Generalize the regions appearing in result0 if possible - let new_vars = self.infcx().region_vars_confined_to_snapshot(snapshot); - let span = self.trace().origin.span(); + let new_vars = self.infcx.region_vars_confined_to_snapshot(snapshot); + let span = self.trace.origin.span(); let result1 = fold_regions_in( self.tcx(), &result0, - |r, debruijn| generalize_region(self.infcx(), span, snapshot, debruijn, + |r, debruijn| generalize_region(self.infcx, span, snapshot, debruijn, &new_vars, &a_map, &a_vars, &b_vars, r)); @@ -332,17 +333,19 @@ impl<'tcx,C> HigherRankedRelations<'tcx> for C } } -fn var_ids<'tcx, T: Combine<'tcx>>(combiner: &T, - map: &FnvHashMap) - -> Vec { - map.iter().map(|(_, r)| match *r { - ty::ReInfer(ty::ReVar(r)) => { r } - r => { - combiner.infcx().tcx.sess.span_bug( - combiner.trace().origin.span(), - &format!("found non-region-vid: {:?}", r)); - } - }).collect() +fn var_ids<'a, 'tcx>(fields: &CombineFields<'a, 'tcx>, + map: &FnvHashMap) + -> Vec { + map.iter() + .map(|(_, r)| match *r { + ty::ReInfer(ty::ReVar(r)) => { r } + r => { + fields.tcx().sess.span_bug( + fields.trace.origin.span(), + &format!("found non-region-vid: {:?}", r)); + } + }) + .collect() } fn is_var_in_set(new_vars: &[ty::RegionVid], r: ty::Region) -> bool { @@ -356,8 +359,8 @@ fn fold_regions_in<'tcx, T, F>(tcx: &ty::ctxt<'tcx>, unbound_value: &T, mut fldr: F) -> T - where T : Combineable<'tcx>, - F : FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, + where T: TypeFoldable<'tcx>, + F: FnMut(ty::Region, ty::DebruijnIndex) -> ty::Region, { unbound_value.fold_with(&mut ty_fold::RegionFolder::new(tcx, &mut |region, current_depth| { // we should only be encountering "escaping" late-bound regions here, diff --git a/src/librustc/middle/infer/lattice.rs b/src/librustc/middle/infer/lattice.rs index 9c764628c14f8..57001083b03e2 100644 --- a/src/librustc/middle/infer/lattice.rs +++ b/src/librustc/middle/infer/lattice.rs @@ -29,48 +29,32 @@ //! over a `LatticeValue`, which is a value defined with respect to //! a lattice. -use super::*; -use super::combine::*; -use super::glb::Glb; -use super::lub::Lub; +use super::combine; +use super::InferCtxt; use middle::ty::TyVar; use middle::ty::{self, Ty}; +use middle::ty_relate::{RelateResult, TypeRelation}; use util::ppaux::Repr; -pub trait LatticeDir<'tcx> { +pub trait LatticeDir<'f,'tcx> : TypeRelation<'f,'tcx> { + fn infcx(&self) -> &'f InferCtxt<'f, 'tcx>; + // Relates the type `v` to `a` and `b` such that `v` represents // the LUB/GLB of `a` and `b` as appropriate. - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()>; -} - -impl<'a, 'tcx> LatticeDir<'tcx> for Lub<'a, 'tcx> { - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> { - let sub = self.sub(); - try!(sub.tys(a, v)); - try!(sub.tys(b, v)); - Ok(()) - } -} - -impl<'a, 'tcx> LatticeDir<'tcx> for Glb<'a, 'tcx> { - fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, ()> { - let sub = self.sub(); - try!(sub.tys(v, a)); - try!(sub.tys(v, b)); - Ok(()) - } + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()>; } -pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L, - a: Ty<'tcx>, - b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> +pub fn super_lattice_tys<'a,'tcx,L:LatticeDir<'a,'tcx>>(this: &mut L, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where 'tcx: 'a { debug!("{}.lattice_tys({}, {})", this.tag(), - a.repr(this.infcx().tcx), - b.repr(this.infcx().tcx)); + a.repr(this.tcx()), + b.repr(this.tcx())); if a == b { return Ok(a); @@ -95,7 +79,7 @@ pub fn super_lattice_tys<'tcx, L:LatticeDir<'tcx>+Combine<'tcx>>(this: &L, } _ => { - super_tys(this, a, b) + combine::super_combine_tys(this.infcx(), this, a, b) } } } diff --git a/src/librustc/middle/infer/lub.rs b/src/librustc/middle/infer/lub.rs index 5000ab32ff671..f456687be13ac 100644 --- a/src/librustc/middle/infer/lub.rs +++ b/src/librustc/middle/infer/lub.rs @@ -8,67 +8,80 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::*; +use super::combine::CombineFields; use super::higher_ranked::HigherRankedRelations; -use super::lattice::*; -use super::cres; +use super::InferCtxt; +use super::lattice::{self, LatticeDir}; use super::Subtype; use middle::ty::{self, Ty}; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; use util::ppaux::Repr; /// "Least upper bound" (common supertype) -pub struct Lub<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Lub<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Lub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Lub<'f, 'tcx> { - Lub { fields: cf } +impl<'a, 'tcx> Lub<'a, 'tcx> { + pub fn new(fields: CombineFields<'a, 'tcx>) -> Lub<'a, 'tcx> { + Lub { fields: fields } + } } -impl<'f, 'tcx> Combine<'tcx> for Lub<'f, 'tcx> { - fn tag(&self) -> String { "Lub".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Lub<'a, 'tcx> { + fn tag(&self) -> &'static str { "Lub" } + + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.tcx() } + + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Bivariant => self.bivariate().tys(a, b), - ty::Contravariant => self.glb().tys(a, b), + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.glb().relate(a, b), } } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> - { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Bivariant => self.bivariate().regions(a, b), - ty::Contravariant => self.glb().regions(a, b), - } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + lattice::super_lattice_tys(self, a, b) } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { debug!("{}.regions({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - Ok(self.infcx().region_vars.lub_regions(Subtype(self.trace()), a, b)) + let origin = Subtype(self.fields.trace.clone()); + Ok(self.fields.infcx.region_vars.lub_regions(origin, a, b)) } - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - super_lattice_tys(self, a, b) + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a, 'tcx> + { + self.fields.higher_ranked_lub(a, b) } +} - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> - { - self.higher_ranked_lub(a, b) +impl<'a, 'tcx> LatticeDir<'a,'tcx> for Lub<'a, 'tcx> { + fn infcx(&self) -> &'a InferCtxt<'a,'tcx> { + self.fields.infcx + } + + fn relate_bound(&self, v: Ty<'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, ()> { + let mut sub = self.fields.sub(); + try!(sub.relate(&a, &v)); + try!(sub.relate(&b, &v)); + Ok(()) } } + diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs index 4cc9b65c2dab3..b11e25c059d08 100644 --- a/src/librustc/middle/infer/mod.rs +++ b/src/librustc/middle/infer/mod.rs @@ -28,7 +28,8 @@ use middle::ty::{TyVid, IntVid, FloatVid, RegionVid, UnconstrainedNumeric}; use middle::ty::replace_late_bound_regions; use middle::ty::{self, Ty}; use middle::ty_fold::{TypeFolder, TypeFoldable}; -use std::cell::RefCell; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use std::cell::{RefCell}; use std::fmt; use std::rc::Rc; use syntax::ast; @@ -38,12 +39,9 @@ use util::nodemap::FnvHashMap; use util::ppaux::ty_to_string; use util::ppaux::{Repr, UserString}; -use self::combine::{Combine, Combineable, CombineFields}; +use self::combine::CombineFields; use self::region_inference::{RegionVarBindings, RegionSnapshot}; -use self::equate::Equate; -use self::sub::Sub; -use self::lub::Lub; -use self::unify::{UnificationTable, InferCtxtMethodsForSimplyUnifiableTypes}; +use self::unify::{ToType, UnificationTable}; use self::error_reporting::ErrorReporting; pub mod bivariate; @@ -62,9 +60,7 @@ pub mod type_variable; pub mod unify; pub type Bound = Option; - -pub type cres<'tcx, T> = Result>; // "combine result" -pub type ures<'tcx> = cres<'tcx, ()>; // "unify result" +pub type UnitResult<'tcx> = RelateResult<'tcx, ()>; // "unify result" pub type fres = Result; // "fixup result" pub struct InferCtxt<'a, 'tcx: 'a> { @@ -265,7 +261,7 @@ pub enum LateBoundRegionConversionTime { /// /// See `error_reporting.rs` for more details #[derive(Clone, Debug)] -pub enum RegionVariableOrigin<'tcx> { +pub enum RegionVariableOrigin { // Region variables created for ill-categorized reasons, // mostly indicates places in need of refactoring MiscVariable(Span), @@ -280,7 +276,7 @@ pub enum RegionVariableOrigin<'tcx> { Autoref(Span), // Regions created as part of an automatic coercion - Coercion(TypeTrace<'tcx>), + Coercion(Span), // Region variables created as the values for early-bound regions EarlyBoundRegion(Span, ast::Name), @@ -294,7 +290,7 @@ pub enum RegionVariableOrigin<'tcx> { BoundRegionInCoherence(ast::Name), } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum fixup_err { unresolved_int_ty(IntVid), unresolved_float_ty(FloatVid), @@ -343,8 +339,7 @@ pub fn common_supertype<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, values: Types(expected_found(a_is_expected, a, b)) }; - let result = - cx.commit_if_ok(|| cx.lub(a_is_expected, trace.clone()).tys(a, b)); + let result = cx.commit_if_ok(|_| cx.lub(a_is_expected, trace.clone()).relate(&a, &b)); match result { Ok(t) => t, Err(ref err) => { @@ -359,29 +354,28 @@ pub fn mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok(|| { - cx.sub_types(a_is_expected, origin, a, b) - }) + cx.sub_types(a_is_expected, origin, a, b) } pub fn can_mk_subty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> { + -> UnitResult<'tcx> { debug!("can_mk_subty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); cx.probe(|_| { let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, a, b)) }; - cx.sub(true, trace).tys(a, b).to_ures() + cx.sub(true, trace).relate(&a, &b).map(|_| ()) }) } -pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) -> ures<'tcx> +pub fn can_mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, a: Ty<'tcx>, b: Ty<'tcx>) + -> UnitResult<'tcx> { cx.can_equate(&a, &b) } @@ -401,11 +395,10 @@ pub fn mk_eqty<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("mk_eqty({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok( - || cx.eq_types(a_is_expected, origin, a, b)) + cx.commit_if_ok(|_| cx.eq_types(a_is_expected, origin, a, b)) } pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, @@ -413,12 +406,11 @@ pub fn mk_sub_poly_trait_refs<'a, 'tcx>(cx: &InferCtxt<'a, 'tcx>, origin: TypeOrigin, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("mk_sub_trait_refs({} <: {})", a.repr(cx.tcx), b.repr(cx.tcx)); - cx.commit_if_ok( - || cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) + cx.commit_if_ok(|_| cx.sub_poly_trait_refs(a_is_expected, origin, a.clone(), b.clone())) } fn expected_found(a_is_expected: bool, @@ -433,57 +425,6 @@ fn expected_found(a_is_expected: bool, } } -trait then<'tcx> { - fn then(&self, f: F) -> Result> where - T: Clone, - F: FnOnce() -> Result>; -} - -impl<'tcx> then<'tcx> for ures<'tcx> { - fn then(&self, f: F) -> Result> where - T: Clone, - F: FnOnce() -> Result>, - { - self.and_then(move |_| f()) - } -} - -trait ToUres<'tcx> { - fn to_ures(&self) -> ures<'tcx>; -} - -impl<'tcx, T> ToUres<'tcx> for cres<'tcx, T> { - fn to_ures(&self) -> ures<'tcx> { - match *self { - Ok(ref _v) => Ok(()), - Err(ref e) => Err((*e)) - } - } -} - -trait CresCompare<'tcx, T> { - fn compare(&self, t: T, f: F) -> cres<'tcx, T> where - F: FnOnce() -> ty::type_err<'tcx>; -} - -impl<'tcx, T:Clone + PartialEq> CresCompare<'tcx, T> for cres<'tcx, T> { - fn compare(&self, t: T, f: F) -> cres<'tcx, T> where - F: FnOnce() -> ty::type_err<'tcx>, - { - (*self).clone().and_then(move |s| { - if s == t { - (*self).clone() - } else { - Err(f()) - } - }) - } -} - -pub fn uok<'tcx>() -> ures<'tcx> { - Ok(()) -} - #[must_use = "once you start a snapshot, you should always consume it"] pub struct CombinedSnapshot { type_snapshot: type_variable::Snapshot, @@ -512,41 +453,56 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { use middle::ty::UnconstrainedNumeric::{Neither, UnconstrainedInt, UnconstrainedFloat}; match ty.sty { ty::ty_infer(ty::IntVar(vid)) => { - match self.int_unification_table.borrow_mut().get(self.tcx, vid).value { - None => UnconstrainedInt, - _ => Neither, + if self.int_unification_table.borrow_mut().has_value(vid) { + Neither + } else { + UnconstrainedInt } }, ty::ty_infer(ty::FloatVar(vid)) => { - match self.float_unification_table.borrow_mut().get(self.tcx, vid).value { - None => return UnconstrainedFloat, - _ => Neither, + if self.float_unification_table.borrow_mut().has_value(vid) { + Neither + } else { + UnconstrainedFloat } }, _ => Neither, } } - pub fn combine_fields<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> CombineFields<'b, 'tcx> { + fn combine_fields(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> CombineFields<'a, 'tcx> { CombineFields {infcx: self, a_is_expected: a_is_expected, trace: trace} } - pub fn equate<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Equate<'b, 'tcx> { - Equate(self.combine_fields(a_is_expected, trace)) + // public so that it can be used from the rustc_driver unit tests + pub fn equate(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> equate::Equate<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).equate() } - pub fn sub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Sub<'b, 'tcx> { - Sub(self.combine_fields(a_is_expected, trace)) + // public so that it can be used from the rustc_driver unit tests + pub fn sub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> sub::Sub<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).sub() } - pub fn lub<'b>(&'b self, a_is_expected: bool, trace: TypeTrace<'tcx>) - -> Lub<'b, 'tcx> { - Lub(self.combine_fields(a_is_expected, trace)) + // public so that it can be used from the rustc_driver unit tests + pub fn lub(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> lub::Lub<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).lub() + } + + // public so that it can be used from the rustc_driver unit tests + pub fn glb(&'a self, a_is_expected: bool, trace: TypeTrace<'tcx>) + -> glb::Glb<'a, 'tcx> + { + self.combine_fields(a_is_expected, trace).glb() } fn start_snapshot(&self) -> CombinedSnapshot { @@ -609,11 +565,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - /// Execute `f` and commit the bindings if successful + /// Execute `f` and commit the bindings if closure `f` returns `Ok(_)` pub fn commit_if_ok(&self, f: F) -> Result where - F: FnOnce() -> Result + F: FnOnce(&CombinedSnapshot) -> Result { - self.commit_unconditionally(move || self.try(move |_| f())) + debug!("commit_if_ok()"); + let snapshot = self.start_snapshot(); + let r = f(&snapshot); + debug!("commit_if_ok() -- r.is_ok() = {}", r.is_ok()); + match r { + Ok(_) => { self.commit_from(snapshot); } + Err(_) => { self.rollback_to(snapshot); } + } + r } /// Execute `f` and commit only the region bindings if successful. @@ -628,7 +592,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { float_snapshot, region_vars_snapshot } = self.start_snapshot(); - let r = self.try(move |_| f()); + let r = self.commit_if_ok(|_| f()); // Roll back any non-region bindings - they should be resolved // inside `f`, with, e.g. `resolve_type_vars_if_possible`. @@ -649,25 +613,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { r } - /// Execute `f`, unroll bindings on panic - pub fn try(&self, f: F) -> Result where - F: FnOnce(&CombinedSnapshot) -> Result - { - debug!("try()"); - let snapshot = self.start_snapshot(); - let r = f(&snapshot); - debug!("try() -- r.is_ok() = {}", r.is_ok()); - match r { - Ok(_) => { - self.commit_from(snapshot); - } - Err(_) => { - self.rollback_to(snapshot); - } - } - r - } - /// Execute `f` then unroll any bindings it creates pub fn probe(&self, f: F) -> R where F: FnOnce(&CombinedSnapshot) -> R, @@ -691,12 +636,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("sub_types({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.sub(a_is_expected, trace).tys(a, b).to_ures() + self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) }) } @@ -705,11 +650,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Ty<'tcx>, b: Ty<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace::types(origin, a_is_expected, a, b); - self.equate(a_is_expected, trace).tys(a, b).to_ures() + self.equate(a_is_expected, trace).relate(&a, &b).map(|_| ()) }) } @@ -718,17 +663,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: Rc>, b: Rc>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("sub_trait_refs({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace { origin: origin, values: TraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).trait_refs(&*a, &*b).to_ures() + self.sub(a_is_expected, trace).relate(&*a, &*b).map(|_| ()) }) } @@ -737,17 +682,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { origin: TypeOrigin, a: ty::PolyTraitRef<'tcx>, b: ty::PolyTraitRef<'tcx>) - -> ures<'tcx> + -> UnitResult<'tcx> { debug!("sub_poly_trait_refs({} <: {})", a.repr(self.tcx), b.repr(self.tcx)); - self.commit_if_ok(|| { + self.commit_if_ok(|_| { let trace = TypeTrace { origin: origin, values: PolyTraitRefs(expected_found(a_is_expected, a.clone(), b.clone())) }; - self.sub(a_is_expected, trace).binders(&a, &b).to_ures() + self.sub(a_is_expected, trace).relate(&a, &b).map(|_| ()) }) } @@ -774,7 +719,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn leak_check(&self, skol_map: &SkolemizationMap, snapshot: &CombinedSnapshot) - -> ures<'tcx> + -> UnitResult<'tcx> { /*! See `higher_ranked::leak_check` */ @@ -799,8 +744,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn equality_predicate(&self, span: Span, predicate: &ty::PolyEquatePredicate<'tcx>) - -> ures<'tcx> { - self.try(|snapshot| { + -> UnitResult<'tcx> { + self.commit_if_ok(|snapshot| { let (ty::EquatePredicate(a, b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); let origin = EquatePredicate(span); @@ -812,8 +757,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn region_outlives_predicate(&self, span: Span, predicate: &ty::PolyRegionOutlivesPredicate) - -> ures<'tcx> { - self.try(|snapshot| { + -> UnitResult<'tcx> { + self.commit_if_ok(|snapshot| { let (ty::OutlivesPredicate(r_a, r_b), skol_map) = self.skolemize_late_bound_regions(predicate, snapshot); let origin = RelateRegionParamBound(span); @@ -852,7 +797,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { .new_key(None) } - pub fn next_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> ty::Region { + pub fn next_region_var(&self, origin: RegionVariableOrigin) -> ty::Region { ty::ReInfer(ty::ReVar(self.region_vars.new_region_var(origin))) } @@ -948,12 +893,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } ty::ty_infer(ty::IntVar(v)) => { - self.probe_var(v) + self.int_unification_table + .borrow_mut() + .probe(v) + .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } ty::ty_infer(ty::FloatVar(v)) => { - self.probe_var(v) + self.float_unification_table + .borrow_mut() + .probe(v) + .map(|v| v.to_type(self.tcx)) .unwrap_or(typ) } @@ -1104,8 +1055,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.region_vars.verify_generic_bound(origin, kind, a, bs); } - pub fn can_equate(&self, a: &T, b: &T) -> ures<'tcx> - where T : Combineable<'tcx> + Repr<'tcx> + pub fn can_equate<'b,T>(&'b self, a: &T, b: &T) -> UnitResult<'tcx> + where T: Relate<'b,'tcx> + Repr<'tcx> { debug!("can_equate({}, {})", a.repr(self.tcx), b.repr(self.tcx)); self.probe(|_| { @@ -1116,9 +1067,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let e = self.tcx.types.err; let trace = TypeTrace { origin: Misc(codemap::DUMMY_SP), values: Types(expected_found(true, e, e)) }; - let eq = self.equate(true, trace); - Combineable::combine(&eq, a, b) - }).to_ures() + self.equate(true, trace).relate(a, b) + }).map(|_| ()) } } @@ -1304,14 +1254,14 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> { } } -impl<'tcx> RegionVariableOrigin<'tcx> { +impl RegionVariableOrigin { pub fn span(&self) -> Span { match *self { MiscVariable(a) => a, PatternRegion(a) => a, AddrOfRegion(a) => a, Autoref(a) => a, - Coercion(ref a) => a.span(), + Coercion(a) => a, EarlyBoundRegion(a, _) => a, LateBoundRegion(a, _, _) => a, BoundRegionInCoherence(_) => codemap::DUMMY_SP, @@ -1320,7 +1270,7 @@ impl<'tcx> RegionVariableOrigin<'tcx> { } } -impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> { +impl<'tcx> Repr<'tcx> for RegionVariableOrigin { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { match *self { MiscVariable(a) => { @@ -1333,7 +1283,7 @@ impl<'tcx> Repr<'tcx> for RegionVariableOrigin<'tcx> { format!("AddrOfRegion({})", a.repr(tcx)) } Autoref(a) => format!("Autoref({})", a.repr(tcx)), - Coercion(ref a) => format!("Coercion({})", a.repr(tcx)), + Coercion(a) => format!("Coercion({})", a.repr(tcx)), EarlyBoundRegion(a, b) => { format!("EarlyBoundRegion({},{})", a.repr(tcx), b.repr(tcx)) } diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs index b539dded12e8a..d41fdc5f09acd 100644 --- a/src/librustc/middle/infer/region_inference/mod.rs +++ b/src/librustc/middle/infer/region_inference/mod.rs @@ -18,7 +18,6 @@ pub use self::RegionResolutionError::*; pub use self::VarValue::*; use self::Classification::*; -use super::cres; use super::{RegionVariableOrigin, SubregionOrigin, TypeTrace, MiscVariable}; use middle::region; @@ -26,6 +25,7 @@ use middle::ty::{self, Ty}; use middle::ty::{BoundRegion, FreeRegion, Region, RegionVid}; use middle::ty::{ReEmpty, ReStatic, ReInfer, ReFree, ReEarlyBound}; use middle::ty::{ReLateBound, ReScope, ReVar, ReSkolemized, BrFresh}; +use middle::ty_relate::RelateResult; use middle::graph; use middle::graph::{Direction, NodeIndex}; use util::common::indenter; @@ -74,13 +74,13 @@ pub enum GenericKind<'tcx> { Projection(ty::ProjectionTy<'tcx>), } -#[derive(Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct TwoRegions { a: Region, b: Region, } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum UndoLogEntry { OpenSnapshot, CommitedSnapshot, @@ -91,7 +91,7 @@ pub enum UndoLogEntry { AddCombination(CombineMapType, TwoRegions) } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum CombineMapType { Lub, Glb } @@ -115,7 +115,7 @@ pub enum RegionResolutionError<'tcx> { /// Could not infer a value for `v` because `sub_r <= v` (due to /// `sub_origin`) but `v <= sup_r` (due to `sup_origin`) and /// `sub_r <= sup_r` does not hold. - SubSupConflict(RegionVariableOrigin<'tcx>, + SubSupConflict(RegionVariableOrigin, SubregionOrigin<'tcx>, Region, SubregionOrigin<'tcx>, Region), @@ -124,7 +124,7 @@ pub enum RegionResolutionError<'tcx> { /// Could not infer a value for `v` because `v <= r1` (due to /// `origin1`) and `v <= r2` (due to `origin2`) and /// `r1` and `r2` have no intersection. - SupSupConflict(RegionVariableOrigin<'tcx>, + SupSupConflict(RegionVariableOrigin, SubregionOrigin<'tcx>, Region, SubregionOrigin<'tcx>, Region), @@ -132,7 +132,7 @@ pub enum RegionResolutionError<'tcx> { /// more specific errors message by suggesting to the user where they /// should put a lifetime. In those cases we process and put those errors /// into `ProcessedErrors` before we do any reporting. - ProcessedErrors(Vec>, + ProcessedErrors(Vec, Vec<(TypeTrace<'tcx>, ty::type_err<'tcx>)>, Vec), } @@ -168,7 +168,7 @@ pub type CombineMap = FnvHashMap; pub struct RegionVarBindings<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, - var_origins: RefCell>>, + var_origins: RefCell>, // Constraints of the form `A <= B` introduced by the region // checker. Here at least one of `A` and `B` must be a region @@ -316,7 +316,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { len as u32 } - pub fn new_region_var(&self, origin: RegionVariableOrigin<'tcx>) -> RegionVid { + pub fn new_region_var(&self, origin: RegionVariableOrigin) -> RegionVid { let id = self.num_vars(); self.var_origins.borrow_mut().push(origin.clone()); let vid = RegionVid { index: id }; @@ -798,7 +798,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// regions are given as argument, in any order, a consistent result is returned. fn lub_free_regions(&self, a: &FreeRegion, - b: &FreeRegion) -> ty::Region + b: &FreeRegion) + -> ty::Region { return match a.cmp(b) { Less => helper(self, a, b), @@ -823,7 +824,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn glb_concrete_regions(&self, a: Region, b: Region) - -> cres<'tcx, Region> { + -> RelateResult<'tcx, Region> + { debug!("glb_concrete_regions({:?}, {:?})", a, b); match (a, b) { (ReLateBound(..), _) | @@ -898,7 +900,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { /// returned. fn glb_free_regions(&self, a: &FreeRegion, - b: &FreeRegion) -> cres<'tcx, ty::Region> + b: &FreeRegion) + -> RelateResult<'tcx, ty::Region> { return match a.cmp(b) { Less => helper(self, a, b), @@ -908,7 +911,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { fn helper<'a, 'tcx>(this: &RegionVarBindings<'a, 'tcx>, a: &FreeRegion, - b: &FreeRegion) -> cres<'tcx, ty::Region> + b: &FreeRegion) -> RelateResult<'tcx, ty::Region> { if this.tcx.region_maps.sub_free_region(*a, *b) { Ok(ty::ReFree(*a)) @@ -926,7 +929,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { region_a: ty::Region, region_b: ty::Region, scope_a: region::CodeExtent, - scope_b: region::CodeExtent) -> cres<'tcx, Region> + scope_b: region::CodeExtent) + -> RelateResult<'tcx, Region> { // We want to generate the intersection of two // scopes or two free regions. So, if one of @@ -947,10 +951,10 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> { // ______________________________________________________________________ -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] enum Classification { Expanding, Contracting } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum VarValue { NoValue, Value(Region), ErrorValue } struct VarData { diff --git a/src/librustc/middle/infer/sub.rs b/src/librustc/middle/infer/sub.rs index 5d23fe3f1348d..31b654a5b3fd3 100644 --- a/src/librustc/middle/infer/sub.rs +++ b/src/librustc/middle/infer/sub.rs @@ -8,64 +8,49 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use super::combine::*; -use super::cres; +use super::combine::{self, CombineFields}; use super::higher_ranked::HigherRankedRelations; use super::Subtype; use super::type_variable::{SubtypeOf, SupertypeOf}; use middle::ty::{self, Ty}; use middle::ty::TyVar; -use util::ppaux::Repr; +use middle::ty_relate::{Relate, RelateResult, TypeRelation}; +use util::ppaux::{Repr}; /// "Greatest lower bound" (common subtype) -pub struct Sub<'f, 'tcx: 'f> { - fields: CombineFields<'f, 'tcx> +pub struct Sub<'a, 'tcx: 'a> { + fields: CombineFields<'a, 'tcx> } -#[allow(non_snake_case)] -pub fn Sub<'f, 'tcx>(cf: CombineFields<'f, 'tcx>) -> Sub<'f, 'tcx> { - Sub { fields: cf } +impl<'a, 'tcx> Sub<'a, 'tcx> { + pub fn new(f: CombineFields<'a, 'tcx>) -> Sub<'a, 'tcx> { + Sub { fields: f } + } } -impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { - fn tag(&self) -> String { "Sub".to_string() } - fn fields<'a>(&'a self) -> &'a CombineFields<'a, 'tcx> { &self.fields } - - fn tys_with_variance(&self, v: ty::Variance, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, Ty<'tcx>> - { - match v { - ty::Invariant => self.equate().tys(a, b), - ty::Covariant => self.tys(a, b), - ty::Bivariant => self.bivariate().tys(a, b), - ty::Contravariant => Sub(self.fields.switch_expected()).tys(b, a), - } - } +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Sub<'a, 'tcx> { + fn tag(&self) -> &'static str { "Sub" } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.fields.infcx.tcx } + fn a_is_expected(&self) -> bool { self.fields.a_is_expected } - fn regions_with_variance(&self, v: ty::Variance, a: ty::Region, b: ty::Region) - -> cres<'tcx, ty::Region> + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> { - match v { - ty::Invariant => self.equate().regions(a, b), - ty::Covariant => self.regions(a, b), - ty::Bivariant => self.bivariate().regions(a, b), - ty::Contravariant => Sub(self.fields.switch_expected()).regions(b, a), + match variance { + ty::Invariant => self.fields.equate().relate(a, b), + ty::Covariant => self.relate(a, b), + ty::Bivariant => self.fields.bivariate().relate(a, b), + ty::Contravariant => self.fields.switch_expected().sub().relate(b, a), } } - fn regions(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ty::Region> { - debug!("{}.regions({}, {})", - self.tag(), - a.repr(self.tcx()), - b.repr(self.tcx())); - self.infcx().region_vars.make_subregion(Subtype(self.trace()), a, b); - Ok(a) - } + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({}, {})", self.tag(), a.repr(self.tcx()), b.repr(self.tcx())); - fn tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> cres<'tcx, Ty<'tcx>> { - debug!("{}.tys({}, {})", self.tag(), - a.repr(self.tcx()), b.repr(self.tcx())); if a == b { return Ok(a); } let infcx = self.fields.infcx; @@ -80,8 +65,8 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } (&ty::ty_infer(TyVar(a_id)), _) => { try!(self.fields - .switch_expected() - .instantiate(b, SupertypeOf, a_id)); + .switch_expected() + .instantiate(b, SupertypeOf, a_id)); Ok(a) } (_, &ty::ty_infer(TyVar(b_id))) => { @@ -94,14 +79,25 @@ impl<'f, 'tcx> Combine<'tcx> for Sub<'f, 'tcx> { } _ => { - super_tys(self, a, b) + combine::super_combine_tys(self.fields.infcx, self, a, b) } } } - fn binders(&self, a: &ty::Binder, b: &ty::Binder) -> cres<'tcx, ty::Binder> - where T : Combineable<'tcx> + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({}, {})", + self.tag(), + a.repr(self.tcx()), + b.repr(self.tcx())); + let origin = Subtype(self.fields.trace.clone()); + self.fields.infcx.region_vars.make_subregion(origin, a, b); + Ok(a) + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> { - self.higher_ranked_sub(a, b) + self.fields.higher_ranked_sub(a, b) } } diff --git a/src/librustc/middle/infer/type_variable.rs b/src/librustc/middle/infer/type_variable.rs index 553ef9afc2816..03612a6c1ae5b 100644 --- a/src/librustc/middle/infer/type_variable.rs +++ b/src/librustc/middle/infer/type_variable.rs @@ -47,7 +47,7 @@ struct Delegate<'tcx>(PhantomData<&'tcx ()>); type Relation = (RelationDir, ty::TyVid); -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum RelationDir { SubtypeOf, SupertypeOf, EqTo, BiTo } diff --git a/src/librustc/middle/infer/unify.rs b/src/librustc/middle/infer/unify.rs index 8a736d47b5d89..4bbced1d75caf 100644 --- a/src/librustc/middle/infer/unify.rs +++ b/src/librustc/middle/infer/unify.rs @@ -12,11 +12,8 @@ pub use self::VarValue::*; use std::marker; -use middle::ty::{expected_found, IntVarValue}; +use middle::ty::{IntVarValue}; use middle::ty::{self, Ty}; -use middle::infer::{uok, ures}; -use middle::infer::InferCtxt; -use std::cell::RefCell; use std::fmt::Debug; use std::marker::PhantomData; use syntax::ast; @@ -35,14 +32,9 @@ use util::snapshot_vec as sv; pub trait UnifyKey : Clone + Debug + PartialEq { type Value : UnifyValue; - fn index(&self) -> usize; + fn index(&self) -> u32; - fn from_index(u: usize) -> Self; - - // Given an inference context, returns the unification table - // appropriate to this key type. - fn unification_table<'v>(infcx: &'v InferCtxt) - -> &'v RefCell>; + fn from_index(u: u32) -> Self; fn tag(k: Option) -> &'static str; } @@ -92,7 +84,7 @@ pub struct Node { pub rank: usize, } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Delegate(PhantomData); // We can't use V:LatticeValue, much as I would like to, @@ -130,21 +122,25 @@ impl UnificationTable { pub fn new_key(&mut self, value: K::Value) -> K { let index = self.values.push(Root(value, 0)); - let k = UnifyKey::from_index(index); + let k = UnifyKey::from_index(index as u32); debug!("{}: created new key: {:?}", UnifyKey::tag(None::), k); k } - /// Find the root node for `vid`. This uses the standard union-find algorithm with path - /// compression: http://en.wikipedia.org/wiki/Disjoint-set_data_structure - pub fn get(&mut self, tcx: &ty::ctxt, vid: K) -> Node { - let index = vid.index(); + /// Find the root node for `vid`. This uses the standard + /// union-find algorithm with path compression: + /// . + /// + /// NB. This is a building-block operation and you would probably + /// prefer to call `probe` below. + fn get(&mut self, vid: K) -> Node { + let index = vid.index() as usize; let value = (*self.values.get(index)).clone(); match value { Redirect(redirect) => { - let node: Node = self.get(tcx, redirect.clone()); + let node: Node = self.get(redirect.clone()); if node.key != redirect { // Path compression self.values.set(index, Redirect(node.key.clone())); @@ -158,58 +154,58 @@ impl UnificationTable { } fn is_root(&self, key: &K) -> bool { - match *self.values.get(key.index()) { + let index = key.index() as usize; + match *self.values.get(index) { Redirect(..) => false, Root(..) => true, } } - /// Sets the value for `vid` to `new_value`. `vid` MUST be a root node! Also, we must be in the - /// middle of a snapshot. - pub fn set<'tcx>(&mut self, - _tcx: &ty::ctxt<'tcx>, - key: K, - new_value: VarValue) - { + /// Sets the value for `vid` to `new_value`. `vid` MUST be a root + /// node! This is an internal operation used to impl other things. + fn set(&mut self, key: K, new_value: VarValue) { assert!(self.is_root(&key)); debug!("Updating variable {:?} to {:?}", key, new_value); - self.values.set(key.index(), new_value); + let index = key.index() as usize; + self.values.set(index, new_value); } - /// Either redirects node_a to node_b or vice versa, depending on the relative rank. Returns - /// the new root and rank. You should then update the value of the new root to something - /// suitable. - pub fn unify<'tcx>(&mut self, - tcx: &ty::ctxt<'tcx>, - node_a: &Node, - node_b: &Node) - -> (K, usize) - { + /// Either redirects `node_a` to `node_b` or vice versa, depending + /// on the relative rank. The value associated with the new root + /// will be `new_value`. + /// + /// NB: This is the "union" operation of "union-find". It is + /// really more of a building block. If the values associated with + /// your key are non-trivial, you would probably prefer to call + /// `unify_var_var` below. + fn unify(&mut self, node_a: &Node, node_b: &Node, new_value: K::Value) { debug!("unify(node_a(id={:?}, rank={:?}), node_b(id={:?}, rank={:?}))", node_a.key, node_a.rank, node_b.key, node_b.rank); - if node_a.rank > node_b.rank { + let (new_root, new_rank) = if node_a.rank > node_b.rank { // a has greater rank, so a should become b's parent, // i.e., b should redirect to a. - self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); + self.set(node_b.key.clone(), Redirect(node_a.key.clone())); (node_a.key.clone(), node_a.rank) } else if node_a.rank < node_b.rank { // b has greater rank, so a should redirect to b. - self.set(tcx, node_a.key.clone(), Redirect(node_b.key.clone())); + self.set(node_a.key.clone(), Redirect(node_b.key.clone())); (node_b.key.clone(), node_b.rank) } else { // If equal, redirect one to the other and increment the // other's rank. assert_eq!(node_a.rank, node_b.rank); - self.set(tcx, node_b.key.clone(), Redirect(node_a.key.clone())); + self.set(node_b.key.clone(), Redirect(node_a.key.clone())); (node_a.key.clone(), node_a.rank + 1) - } + }; + + self.set(new_root, Root(new_value, new_rank)); } } @@ -223,69 +219,26 @@ impl sv::SnapshotVecDelegate for Delegate { } /////////////////////////////////////////////////////////////////////////// -// Code to handle simple keys like ints, floats---anything that -// doesn't have a subtyping relationship we need to worry about. - -/// Indicates a type that does not have any kind of subtyping -/// relationship. -pub trait SimplyUnifiable<'tcx> : Clone + PartialEq + Debug { - fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; - fn to_type_err(expected_found) -> ty::type_err<'tcx>; -} - -pub fn err<'tcx, V:SimplyUnifiable<'tcx>>(a_is_expected: bool, - a_t: V, - b_t: V) - -> ures<'tcx> { - if a_is_expected { - Err(SimplyUnifiable::to_type_err( - ty::expected_found {expected: a_t, found: b_t})) - } else { - Err(SimplyUnifiable::to_type_err( - ty::expected_found {expected: b_t, found: a_t})) - } -} - -pub trait InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> - where K : UnifyKey>, - V : SimplyUnifiable<'tcx>, - Option : UnifyValue, -{ - fn simple_vars(&self, - a_is_expected: bool, - a_id: K, - b_id: K) - -> ures<'tcx>; - fn simple_var_t(&self, - a_is_expected: bool, - a_id: K, - b: V) - -> ures<'tcx>; - fn probe_var(&self, a_id: K) -> Option>; -} - -impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtxt<'a,'tcx> - where K : UnifyKey>, - V : SimplyUnifiable<'tcx>, - Option : UnifyValue, +// Code to handle keys which carry a value, like ints, +// floats---anything that doesn't have a subtyping relationship we +// need to worry about. + +impl<'tcx,K,V> UnificationTable + where K: UnifyKey>, + V: Clone+PartialEq, + Option: UnifyValue, { - /// Unifies two simple keys. Because simple keys do not have any subtyping relationships, if - /// both keys have already been associated with a value, then those two values must be the - /// same. - fn simple_vars(&self, - a_is_expected: bool, - a_id: K, - b_id: K) - -> ures<'tcx> + pub fn unify_var_var(&mut self, + a_id: K, + b_id: K) + -> Result<(),(V,V)> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a: Node = table.borrow_mut().get(tcx, a_id); - let node_b: Node = table.borrow_mut().get(tcx, b_id); + let node_a = self.get(a_id); + let node_b = self.get(b_id); let a_id = node_a.key.clone(); let b_id = node_b.key.clone(); - if a_id == b_id { return uok(); } + if a_id == b_id { return Ok(()); } let combined = { match (&node_a.value, &node_b.value) { @@ -293,61 +246,52 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx None } (&Some(ref v), &None) | (&None, &Some(ref v)) => { - Some((*v).clone()) + Some(v.clone()) } (&Some(ref v1), &Some(ref v2)) => { if *v1 != *v2 { - return err(a_is_expected, (*v1).clone(), (*v2).clone()) + return Err((v1.clone(), v2.clone())); } - Some((*v1).clone()) + Some(v1.clone()) } } }; - let (new_root, new_rank) = table.borrow_mut().unify(tcx, - &node_a, - &node_b); - table.borrow_mut().set(tcx, new_root, Root(combined, new_rank)); - return Ok(()) + Ok(self.unify(&node_a, &node_b, combined)) } /// Sets the value of the key `a_id` to `b`. Because simple keys do not have any subtyping /// relationships, if `a_id` already has a value, it must be the same as `b`. - fn simple_var_t(&self, - a_is_expected: bool, - a_id: K, - b: V) - -> ures<'tcx> + pub fn unify_var_value(&mut self, + a_id: K, + b: V) + -> Result<(),(V,V)> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a = table.borrow_mut().get(tcx, a_id); + let node_a = self.get(a_id); let a_id = node_a.key.clone(); match node_a.value { None => { - table.borrow_mut().set(tcx, a_id, Root(Some(b), node_a.rank)); - return Ok(()); + self.set(a_id, Root(Some(b), node_a.rank)); + Ok(()) } Some(ref a_t) => { if *a_t == b { - return Ok(()); + Ok(()) } else { - return err(a_is_expected, (*a_t).clone(), b); + Err((a_t.clone(), b)) } } } } - fn probe_var(&self, a_id: K) -> Option> { - let tcx = self.tcx; - let table = UnifyKey::unification_table(self); - let node_a = table.borrow_mut().get(tcx, a_id); - match node_a.value { - None => None, - Some(ref a_t) => Some(a_t.to_type(tcx)) - } + pub fn has_value(&mut self, id: K) -> bool { + self.get(id).value.is_some() + } + + pub fn probe(&mut self, a_id: K) -> Option { + self.get(a_id).value.clone() } } @@ -355,33 +299,24 @@ impl<'a,'tcx,V,K> InferCtxtMethodsForSimplyUnifiableTypes<'tcx,K,V> for InferCtx // Integral type keys +pub trait ToType<'tcx> { + fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx>; +} + impl UnifyKey for ty::IntVid { type Value = Option; - - fn index(&self) -> usize { self.index as usize } - - fn from_index(i: usize) -> ty::IntVid { ty::IntVid { index: i as u32 } } - - fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell> { - return &infcx.int_unification_table; - } - - fn tag(_: Option) -> &'static str { - "IntVid" - } + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::IntVid { ty::IntVid { index: i } } + fn tag(_: Option) -> &'static str { "IntVid" } } -impl<'tcx> SimplyUnifiable<'tcx> for IntVarValue { +impl<'tcx> ToType<'tcx> for IntVarValue { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { match *self { ty::IntType(i) => ty::mk_mach_int(tcx, i), ty::UintType(i) => ty::mk_mach_uint(tcx, i), } } - - fn to_type_err(err: expected_found) -> ty::type_err<'tcx> { - return ty::terr_int_mismatch(err); - } } impl UnifyValue for Option { } @@ -390,29 +325,16 @@ impl UnifyValue for Option { } impl UnifyKey for ty::FloatVid { type Value = Option; - - fn index(&self) -> usize { self.index as usize } - - fn from_index(i: usize) -> ty::FloatVid { ty::FloatVid { index: i as u32 } } - - fn unification_table<'v>(infcx: &'v InferCtxt) -> &'v RefCell> { - return &infcx.float_unification_table; - } - - fn tag(_: Option) -> &'static str { - "FloatVid" - } + fn index(&self) -> u32 { self.index } + fn from_index(i: u32) -> ty::FloatVid { ty::FloatVid { index: i } } + fn tag(_: Option) -> &'static str { "FloatVid" } } impl UnifyValue for Option { } -impl<'tcx> SimplyUnifiable<'tcx> for ast::FloatTy { +impl<'tcx> ToType<'tcx> for ast::FloatTy { fn to_type(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { ty::mk_mach_float(tcx, *self) } - - fn to_type_err(err: expected_found) -> ty::type_err<'tcx> { - ty::terr_float_mismatch(err) - } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index b9a82669f65d3..a08de58f909d3 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -46,7 +46,7 @@ macro_rules! lets_do_this { $( $variant:ident, $name:expr, $method:ident; )* ) => { -#[derive(Copy, FromPrimitive, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, FromPrimitive, PartialEq, Eq, Hash)] pub enum LangItem { $($variant),* } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 705f20559afde..d7161607b61eb 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -139,7 +139,7 @@ enum LoopKind<'a> { WhileLoop(&'a Expr), } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] struct Variable(usize); #[derive(Copy, PartialEq)] @@ -159,7 +159,7 @@ impl Clone for LiveNode { } } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] enum LiveNodeKind { FreeVarNode(Span), ExprNode(Span), @@ -245,13 +245,13 @@ struct CaptureInfo { var_nid: NodeId } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] struct LocalInfo { id: NodeId, ident: ast::Ident } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum VarKind { Arg(NodeId, ast::Ident), Local(LocalInfo), @@ -534,7 +534,7 @@ fn invalid_users() -> Users { } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Specials { exit_ln: LiveNode, fallthrough_ln: LiveNode, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 3738e38f68704..85255d04df432 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -199,7 +199,7 @@ pub type cmt<'tcx> = Rc>; // We pun on *T to mean both actual deref of a ptr as well // as accessing of components: -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum deref_kind { deref_ptr(PointerKind), deref_interior(InteriorKind), @@ -263,6 +263,9 @@ pub struct MemCategorizationContext<'t,TYPER:'t> { } impl<'t,TYPER:'t> Copy for MemCategorizationContext<'t,TYPER> {} +impl<'t,TYPER:'t> Clone for MemCategorizationContext<'t,TYPER> { + fn clone(&self) -> MemCategorizationContext<'t,TYPER> { *self } +} pub type McResult = Result; diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 3a253735f925b..d8efb5655aaab 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -32,7 +32,7 @@ pub type ExternalExports = DefIdSet; /// reexporting a public struct doesn't inline the doc). pub type PublicItems = NodeSet; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum LastPrivate { LastMod(PrivateDep), // `use` directives (imports) can refer to two separate definitions in the @@ -46,14 +46,14 @@ pub enum LastPrivate { type_used: ImportUse}, } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum PrivateDep { AllPublic, DependsOn(ast::DefId), } // How an import is used. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum ImportUse { Unused, // The import is not used. Used, // The import is used. diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index b68f8fa9b988d..652f661325206 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -271,7 +271,7 @@ pub struct RegionMaps { /// Carries the node id for the innermost block or match expression, /// for building up the `var_map` which maps ids to the blocks in /// which they were declared. -#[derive(PartialEq, Eq, Debug, Copy)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] enum InnermostDeclaringBlock { None, Block(ast::NodeId), @@ -296,7 +296,7 @@ impl InnermostDeclaringBlock { /// Contextual information for declarations introduced by a statement /// (i.e. `let`). It carries node-id's for statement and enclosing /// block both, as well as the statement's index within the block. -#[derive(PartialEq, Eq, Debug, Copy)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] struct DeclaringStatementContext { stmt_id: ast::NodeId, block_id: ast::NodeId, @@ -312,7 +312,7 @@ impl DeclaringStatementContext { } } -#[derive(PartialEq, Eq, Debug, Copy)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] enum InnermostEnclosingExpr { None, Some(ast::NodeId), @@ -334,7 +334,7 @@ impl InnermostEnclosingExpr { } } -#[derive(Debug, Copy)] +#[derive(Debug, Copy, Clone)] pub struct Context { /// the root of the current region tree. This is typically the id /// of the innermost fn body. Each fn forms its own disjoint tree diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs index 11d073ce72e73..2f2db8f38bd87 100644 --- a/src/librustc/middle/traits/coherence.rs +++ b/src/librustc/middle/traits/coherence.rs @@ -17,15 +17,17 @@ use super::PredicateObligation; use super::project; use super::util; -use middle::subst::{Subst, TypeSpace}; +use middle::subst::{Subst, Substs, TypeSpace}; use middle::ty::{self, ToPolyTraitRef, Ty}; use middle::infer::{self, InferCtxt}; -use std::collections::HashSet; use std::rc::Rc; use syntax::ast; -use syntax::codemap::DUMMY_SP; +use syntax::codemap::{DUMMY_SP, Span}; use util::ppaux::Repr; +#[derive(Copy, Clone)] +struct ParamIsLocal(bool); + /// True if there exist types that satisfy both of the two given impls. pub fn overlapping_impls(infcx: &InferCtxt, impl1_def_id: ast::DefId, @@ -56,10 +58,16 @@ fn overlap(selcx: &mut SelectionContext, a_def_id.repr(selcx.tcx()), b_def_id.repr(selcx.tcx())); - let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, a_def_id); - let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, b_def_id); + let (a_trait_ref, a_obligations) = impl_trait_ref_and_oblig(selcx, + a_def_id, + util::free_substs_for_impl); + + let (b_trait_ref, b_obligations) = impl_trait_ref_and_oblig(selcx, + b_def_id, + util::fresh_type_vars_for_impl); debug!("overlap: a_trait_ref={}", a_trait_ref.repr(selcx.tcx())); + debug!("overlap: b_trait_ref={}", b_trait_ref.repr(selcx.tcx())); // Does `a <: b` hold? If not, no overlap. @@ -74,28 +82,68 @@ fn overlap(selcx: &mut SelectionContext, debug!("overlap: subtraitref check succeeded"); // Are any of the obligations unsatisfiable? If so, no overlap. + let tcx = selcx.tcx(); + let infcx = selcx.infcx(); let opt_failing_obligation = a_obligations.iter() .chain(b_obligations.iter()) + .map(|o| infcx.resolve_type_vars_if_possible(o)) .find(|o| !selcx.evaluate_obligation(o)); if let Some(failing_obligation) = opt_failing_obligation { - debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(selcx.tcx())); - return false; + debug!("overlap: obligation unsatisfiable {}", failing_obligation.repr(tcx)); + return false } true } +pub fn trait_ref_is_knowable<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref: &ty::TraitRef<'tcx>) -> bool +{ + debug!("trait_ref_is_knowable(trait_ref={})", trait_ref.repr(tcx)); + + // if the orphan rules pass, that means that no ancestor crate can + // impl this, so it's up to us. + if orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(false)).is_ok() { + debug!("trait_ref_is_knowable: orphan check passed"); + return true; + } + + // if the trait is not marked fundamental, then it's always possible that + // an ancestor crate will impl this in the future, if they haven't + // already + if + trait_ref.def_id.krate != ast::LOCAL_CRATE && + !ty::has_attr(tcx, trait_ref.def_id, "fundamental") + { + debug!("trait_ref_is_knowable: trait is neither local nor fundamental"); + return false; + } + + // find out when some downstream (or cousin) crate could impl this + // trait-ref, presuming that all the parameters were instantiated + // with downstream types. If not, then it could only be + // implemented by an upstream crate, which means that the impl + // must be visible to us, and -- since the trait is fundamental + // -- we can test. + orphan_check_trait_ref(tcx, trait_ref, ParamIsLocal(true)).is_err() +} + +type SubstsFn = for<'a,'tcx> fn(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx>; + /// Instantiate fresh variables for all bound parameters of the impl /// and return the impl trait ref with those variables substituted. fn impl_trait_ref_and_oblig<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>, - impl_def_id: ast::DefId) + impl_def_id: ast::DefId, + substs_fn: SubstsFn) -> (Rc>, Vec>) { let impl_substs = - &util::fresh_substs_for_impl(selcx.infcx(), DUMMY_SP, impl_def_id); + &substs_fn(selcx.infcx(), DUMMY_SP, impl_def_id); let impl_trait_ref = ty::impl_trait_ref(selcx.tcx(), impl_def_id).unwrap(); let impl_trait_ref = @@ -134,12 +182,12 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, impl_def_id: ast::DefId) -> Result<(), OrphanCheckErr<'tcx>> { - debug!("impl_is_local({})", impl_def_id.repr(tcx)); + debug!("orphan_check({})", impl_def_id.repr(tcx)); // We only except this routine to be invoked on implementations // of a trait, not inherent implementations. let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap(); - debug!("trait_ref={}", trait_ref.repr(tcx)); + debug!("orphan_check: trait_ref={}", trait_ref.repr(tcx)); // If the *trait* is local to the crate, ok. if trait_ref.def_id.krate == ast::LOCAL_CRATE { @@ -148,34 +196,106 @@ pub fn orphan_check<'tcx>(tcx: &ty::ctxt<'tcx>, return Ok(()); } + orphan_check_trait_ref(tcx, &trait_ref, ParamIsLocal(false)) +} + +fn orphan_check_trait_ref<'tcx>(tcx: &ty::ctxt<'tcx>, + trait_ref: &ty::TraitRef<'tcx>, + param_is_local: ParamIsLocal) + -> Result<(), OrphanCheckErr<'tcx>> +{ + debug!("orphan_check_trait_ref(trait_ref={}, param_is_local={})", + trait_ref.repr(tcx), param_is_local.0); + // First, create an ordered iterator over all the type parameters to the trait, with the self // type appearing first. let input_tys = Some(trait_ref.self_ty()); let input_tys = input_tys.iter().chain(trait_ref.substs.types.get_slice(TypeSpace).iter()); - let mut input_tys = input_tys; // Find the first input type that either references a type parameter OR // some local type. - match input_tys.find(|&&input_ty| references_local_or_type_parameter(tcx, input_ty)) { - Some(&input_ty) => { - // Within this first type, check that all type parameters are covered by a local - // type constructor. Note that if there is no local type constructor, then any - // type parameter at all will be an error. - let covered_params = type_parameters_covered_by_ty(tcx, input_ty); - let all_params = type_parameters_reachable_from_ty(input_ty); - for ¶m in all_params.difference(&covered_params) { - return Err(OrphanCheckErr::UncoveredTy(param)); + for input_ty in input_tys { + if ty_is_local(tcx, input_ty, param_is_local) { + debug!("orphan_check_trait_ref: ty_is_local `{}`", input_ty.repr(tcx)); + + // First local input type. Check that there are no + // uncovered type parameters. + let uncovered_tys = uncovered_tys(tcx, input_ty, param_is_local); + for uncovered_ty in uncovered_tys { + if let Some(param) = uncovered_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); + return Err(OrphanCheckErr::UncoveredTy(param)); + } } + + // OK, found local type, all prior types upheld invariant. + return Ok(()); } - None => { - return Err(OrphanCheckErr::NoLocalInputType); + + // Otherwise, enforce invariant that there are no type + // parameters reachable. + if !param_is_local.0 { + if let Some(param) = input_ty.walk().find(|t| is_type_parameter(t)) { + debug!("orphan_check_trait_ref: uncovered type `{}`", param.repr(tcx)); + return Err(OrphanCheckErr::UncoveredTy(param)); + } } } - return Ok(()); + // If we exit above loop, never found a local type. + debug!("orphan_check_trait_ref: no local type"); + return Err(OrphanCheckErr::NoLocalInputType); +} + +fn uncovered_tys<'tcx>(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_is_local: ParamIsLocal) + -> Vec> +{ + if ty_is_local_constructor(tcx, ty, param_is_local) { + vec![] + } else if fundamental_ty(tcx, ty) { + ty.walk_shallow() + .flat_map(|t| uncovered_tys(tcx, t, param_is_local).into_iter()) + .collect() + } else { + vec![ty] + } } -fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { +fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { + match ty.sty { + // FIXME(#20590) straighten story about projection types + ty::ty_projection(..) | ty::ty_param(..) => true, + _ => false, + } +} + +fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>, param_is_local: ParamIsLocal) -> bool +{ + ty_is_local_constructor(tcx, ty, param_is_local) || + fundamental_ty(tcx, ty) && ty.walk_shallow().any(|t| ty_is_local(tcx, t, param_is_local)) +} + +fn fundamental_ty<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool +{ + match ty.sty { + ty::ty_uniq(..) | ty::ty_rptr(..) => + true, + ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) => + ty::has_attr(tcx, def_id, "fundamental"), + ty::ty_trait(ref data) => + ty::has_attr(tcx, data.principal_def_id(), "fundamental"), + _ => + false + } +} + +fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, + ty: Ty<'tcx>, + param_is_local: ParamIsLocal) + -> bool +{ debug!("ty_is_local_constructor({})", ty.repr(tcx)); match ty.sty { @@ -190,11 +310,15 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { ty::ty_ptr(..) | ty::ty_rptr(..) | ty::ty_tup(..) | - ty::ty_param(..) | + ty::ty_infer(..) | ty::ty_projection(..) => { false } + ty::ty_param(..) => { + param_is_local.0 + } + ty::ty_enum(def_id, _) | ty::ty_struct(def_id, _) => { def_id.krate == ast::LOCAL_CRATE @@ -210,7 +334,6 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } ty::ty_closure(..) | - ty::ty_infer(..) | ty::ty_err => { tcx.sess.bug( &format!("ty_is_local invoked on unexpected type: {}", @@ -219,30 +342,4 @@ fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { } } -fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>, - ty: Ty<'tcx>) - -> HashSet> -{ - if ty_is_local_constructor(tcx, ty) { - type_parameters_reachable_from_ty(ty) - } else { - ty.walk_children().flat_map(|t| type_parameters_covered_by_ty(tcx, t).into_iter()).collect() - } -} - -/// All type parameters reachable from `ty` -fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet> { - ty.walk().filter(|&t| is_type_parameter(t)).collect() -} - -fn references_local_or_type_parameter<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool { - ty.walk().any(|ty| is_type_parameter(ty) || ty_is_local_constructor(tcx, ty)) -} -fn is_type_parameter<'tcx>(ty: Ty<'tcx>) -> bool { - match ty.sty { - // FIXME(#20590) straighten story about projection types - ty::ty_projection(..) | ty::ty_param(..) => true, - _ => false, - } -} diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs index 1594d8b2e0d04..7488b8f046e74 100644 --- a/src/librustc/middle/traits/project.rs +++ b/src/librustc/middle/traits/project.rs @@ -81,7 +81,7 @@ pub fn poly_project_and_unify_type<'cx,'tcx>( obligation.repr(selcx.tcx())); let infcx = selcx.infcx(); - infcx.try(|snapshot| { + infcx.commit_if_ok(|snapshot| { let (skol_predicate, skol_map) = infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot); @@ -291,6 +291,7 @@ impl<'a,'b,'tcx> TypeFolder<'tcx> for AssociatedTypeNormalizer<'a,'b,'tcx> { } } +#[derive(Clone)] pub struct Normalized<'tcx,T> { pub value: T, pub obligations: Vec>, diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index 9e4f63dca4565..f7e7d071f8ca4 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -17,6 +17,7 @@ use self::SelectionCandidate::*; use self::BuiltinBoundConditions::*; use self::EvaluationResult::*; +use super::coherence; use super::DerivedObligationCause; use super::project; use super::project::{normalize_with_depth, Normalized}; @@ -38,11 +39,13 @@ use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty}; use middle::infer; use middle::infer::{InferCtxt, TypeFreshener}; use middle::ty_fold::TypeFoldable; +use middle::ty_match; +use middle::ty_relate::TypeRelation; use std::cell::RefCell; -use std::collections::hash_map::HashMap; use std::rc::Rc; use syntax::{abi, ast}; use util::common::ErrorReported; +use util::nodemap::FnvHashMap; use util::ppaux::Repr; pub struct SelectionContext<'cx, 'tcx:'cx> { @@ -81,13 +84,13 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { /// selection-context's freshener. Used to check for recursion. fresh_trait_ref: ty::PolyTraitRef<'tcx>, - previous: Option<&'prev TraitObligationStack<'prev, 'tcx>> + previous: TraitObligationStackList<'prev, 'tcx>, } #[derive(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell>, - SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, + hashmap: RefCell>, + SelectionResult<'tcx, SelectionCandidate<'tcx>>>>, } pub enum MethodMatchResult { @@ -96,7 +99,7 @@ pub enum MethodMatchResult { MethodDidNotMatch, } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum MethodMatchedData { // In the case of a precise match, we don't really need to store // how the match was found. So don't. @@ -245,7 +248,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("select({})", obligation.repr(self.tcx())); assert!(!obligation.predicate.has_escaping_regions()); - let stack = self.push_stack(None, obligation); + let stack = self.push_stack(TraitObligationStackList::empty(), obligation); match try!(self.candidate_from_obligation(&stack)) { None => { self.consider_unification_despite_ambiguity(obligation); @@ -327,7 +330,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("evaluate_obligation({})", obligation.repr(self.tcx())); - self.evaluate_predicate_recursively(None, obligation).may_apply() + self.evaluate_predicate_recursively(TraitObligationStackList::empty(), obligation) + .may_apply() } fn evaluate_builtin_bound_recursively<'o>(&mut self, @@ -346,7 +350,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match obligation { Ok(obligation) => { - self.evaluate_predicate_recursively(Some(previous_stack), &obligation) + self.evaluate_predicate_recursively(previous_stack.list(), &obligation) } Err(ErrorReported) => { EvaluatedToOk @@ -355,7 +359,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_predicates_recursively<'a,'o,I>(&mut self, - stack: Option<&TraitObligationStack<'o, 'tcx>>, + stack: TraitObligationStackList<'o, 'tcx>, predicates: I) -> EvaluationResult<'tcx> where I : Iterator>, 'tcx:'a @@ -372,7 +376,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_predicate_recursively<'o>(&mut self, - previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &PredicateObligation<'tcx>) -> EvaluationResult<'tcx> { @@ -423,14 +427,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn evaluate_obligation_recursively<'o>(&mut self, - previous_stack: Option<&TraitObligationStack<'o, 'tcx>>, + previous_stack: TraitObligationStackList<'o, 'tcx>, obligation: &TraitObligation<'tcx>) -> EvaluationResult<'tcx> { debug!("evaluate_obligation_recursively({})", obligation.repr(self.tcx())); - let stack = self.push_stack(previous_stack.map(|x| x), obligation); + let stack = self.push_stack(previous_stack, obligation); let result = self.evaluate_stack(&stack); @@ -472,7 +476,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { unbound_input_types && (self.intercrate || stack.iter().skip(1).any( - |prev| stack.fresh_trait_ref.def_id() == prev.fresh_trait_ref.def_id())) + |prev| self.match_fresh_trait_refs(&stack.fresh_trait_ref, + &prev.fresh_trait_ref))) { debug!("evaluate_stack({}) --> unbound argument, recursion --> ambiguous", stack.fresh_trait_ref.repr(self.tcx())); @@ -538,7 +543,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation.recursion_depth + 1, skol_map, snapshot); - self.winnow_selection(None, VtableImpl(vtable_impl)).may_apply() + self.winnow_selection(TraitObligationStackList::empty(), + VtableImpl(vtable_impl)).may_apply() } Err(()) => { false @@ -607,6 +613,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Ok(Some(ErrorCandidate)); } + if !self.is_knowable(stack) { + debug!("intercrate not knowable"); + return Ok(None); + } + let candidate_set = try!(self.assemble_candidates(stack)); if candidate_set.ambiguous { @@ -707,6 +718,27 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(candidate)) } + fn is_knowable<'o>(&mut self, + stack: &TraitObligationStack<'o, 'tcx>) + -> bool + { + debug!("is_knowable(intercrate={})", self.intercrate); + + if !self.intercrate { + return true; + } + + let obligation = &stack.obligation; + let predicate = self.infcx().resolve_type_vars_if_possible(&obligation.predicate); + + // ok to skip binder because of the nature of the + // trait-ref-is-knowable check, which does not care about + // bound regions + let trait_ref = &predicate.skip_binder().trait_ref; + + coherence::trait_ref_is_knowable(self.tcx(), trait_ref) + } + fn pick_candidate_cache(&self) -> &SelectionCache<'tcx> { // If there are any where-clauses in scope, then we always use // a cache local to this particular scope. Otherwise, we @@ -1026,7 +1058,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.infcx().probe(move |_| { match self.match_where_clause_trait_ref(stack.obligation, where_clause_trait_ref) { Ok(obligations) => { - self.evaluate_predicates_recursively(Some(stack), obligations.iter()) + self.evaluate_predicates_recursively(stack.list(), obligations.iter()) } Err(()) => { EvaluatedToErr(Unimplemented) @@ -1242,7 +1274,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return; } - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let bound_self_ty = self.infcx.resolve_type_vars_if_possible(&obligation.self_ty()); let (self_ty, _) = @@ -1310,7 +1342,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let result = self.infcx.probe(|_| { let candidate = (*candidate).clone(); match self.confirm_candidate(stack.obligation, candidate) { - Ok(selection) => self.winnow_selection(Some(stack), selection), + Ok(selection) => self.winnow_selection(stack.list(), + selection), Err(error) => EvaluatedToErr(error), } }); @@ -1320,7 +1353,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } fn winnow_selection<'o>(&mut self, - stack: Option<&TraitObligationStack<'o, 'tcx>>, + stack: TraitObligationStackList<'o,'tcx>, selection: Selection<'tcx>) -> EvaluationResult<'tcx> { @@ -1778,7 +1811,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // For each type, produce a vector of resulting obligations let obligations: Result>, _> = bound_types.iter().map(|nested_ty| { - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let (skol_ty, skol_map) = self.infcx().skolemize_late_bound_regions(nested_ty, snapshot); let Normalized { value: normalized_ty, mut obligations } = @@ -1888,7 +1921,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>) { let _: Result<(),()> = - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let result = self.match_projection_obligation_against_bounds_from_trait(obligation, snapshot); @@ -2043,7 +2076,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { trait_def_id, nested); - let trait_obligations: Result,()> = self.infcx.try(|snapshot| { + let trait_obligations: Result,()> = self.infcx.commit_if_ok(|snapshot| { let poly_trait_ref = obligation.predicate.to_poly_trait_ref(); let (trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot); @@ -2077,7 +2110,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // First, create the substitutions by matching the impl again, // this time not in a probe. - self.infcx.try(|snapshot| { + self.infcx.commit_if_ok(|snapshot| { let (skol_obligation_trait_ref, skol_map) = self.infcx().skolemize_late_bound_regions(&obligation.predicate, snapshot); let substs = @@ -2303,9 +2336,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(()); } - let impl_substs = util::fresh_substs_for_impl(self.infcx, - obligation.cause.span, - impl_def_id); + let impl_substs = util::fresh_type_vars_for_impl(self.infcx, + obligation.cause.span, + impl_def_id); let impl_trait_ref = impl_trait_ref.subst(self.tcx(), &impl_substs); @@ -2423,9 +2456,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { { // Create fresh type variables for each type parameter declared // on the impl etc. - let impl_substs = util::fresh_substs_for_impl(self.infcx, - obligation_cause.span, - impl_def_id); + let impl_substs = util::fresh_type_vars_for_impl(self.infcx, + obligation_cause.span, + impl_def_id); // Find the self type for the impl. let impl_self_ty = ty::lookup_item_type(self.tcx(), impl_def_id).ty; @@ -2475,8 +2508,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Miscellany + fn match_fresh_trait_refs(&self, + previous: &ty::PolyTraitRef<'tcx>, + current: &ty::PolyTraitRef<'tcx>) + -> bool + { + let mut matcher = ty_match::Match::new(self.tcx()); + matcher.relate(previous, current).is_ok() + } + fn push_stack<'o,'s:'o>(&mut self, - previous_stack: Option<&'s TraitObligationStack<'s, 'tcx>>, + previous_stack: TraitObligationStackList<'s, 'tcx>, obligation: &'o TraitObligation<'tcx>) -> TraitObligationStack<'o, 'tcx> { @@ -2486,7 +2528,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { TraitObligationStack { obligation: obligation, fresh_trait_ref: fresh_trait_ref, - previous: previous_stack.map(|p| p), // FIXME variance + previous: previous_stack, } } @@ -2634,22 +2676,41 @@ impl<'tcx> Repr<'tcx> for SelectionCandidate<'tcx> { impl<'tcx> SelectionCache<'tcx> { pub fn new() -> SelectionCache<'tcx> { SelectionCache { - hashmap: RefCell::new(HashMap::new()) + hashmap: RefCell::new(FnvHashMap()) } } } -impl<'o, 'tcx> TraitObligationStack<'o, 'tcx> { - fn iter(&self) -> Option<&TraitObligationStack<'o, 'tcx>> { - Some(self) +impl<'o,'tcx> TraitObligationStack<'o,'tcx> { + fn list(&'o self) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList::with(self) } + + fn iter(&'o self) -> TraitObligationStackList<'o,'tcx> { + self.list() + } +} + +#[derive(Copy, Clone)] +struct TraitObligationStackList<'o,'tcx:'o> { + head: Option<&'o TraitObligationStack<'o,'tcx>> } -impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> { +impl<'o,'tcx> TraitObligationStackList<'o,'tcx> { + fn empty() -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: None } + } + + fn with(r: &'o TraitObligationStack<'o,'tcx>) -> TraitObligationStackList<'o,'tcx> { + TraitObligationStackList { head: Some(r) } + } +} + +impl<'o,'tcx> Iterator for TraitObligationStackList<'o,'tcx>{ type Item = &'o TraitObligationStack<'o,'tcx>; - fn next(&mut self) -> Option<&'o TraitObligationStack<'o, 'tcx>> { - match *self { + fn next(&mut self) -> Option<&'o TraitObligationStack<'o,'tcx>> { + match self.head { Some(o) => { *self = o.previous; Some(o) @@ -2659,7 +2720,7 @@ impl<'o, 'tcx> Iterator for Option<&'o TraitObligationStack<'o, 'tcx>> { } } -impl<'o, 'tcx> Repr<'tcx> for TraitObligationStack<'o, 'tcx> { +impl<'o,'tcx> Repr<'tcx> for TraitObligationStack<'o,'tcx> { fn repr(&self, tcx: &ty::ctxt<'tcx>) -> String { format!("TraitObligationStack({})", self.obligation.repr(tcx)) diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs index 7c7db4a64c02e..297cea13207e5 100644 --- a/src/librustc/middle/traits/util.rs +++ b/src/librustc/middle/traits/util.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::region; use middle::subst::{Substs, VecPerParamSpace}; use middle::infer::InferCtxt; use middle::ty::{self, Ty, AsPredicate, ToPolyTraitRef}; @@ -285,7 +286,6 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { } } - /////////////////////////////////////////////////////////////////////////// // Other /////////////////////////////////////////////////////////////////////////// @@ -294,16 +294,44 @@ impl<'tcx,I:Iterator>> Iterator for FilterToTraits { // declared on the impl declaration e.g., `impl for Box<[(A,B)]>` // would return ($0, $1) where $0 and $1 are freshly instantiated type // variables. -pub fn fresh_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, - span: Span, - impl_def_id: ast::DefId) - -> Substs<'tcx> +pub fn fresh_type_vars_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx> { let tcx = infcx.tcx; let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; infcx.fresh_substs_for_generics(span, &impl_generics) } +// determine the `self` type, using fresh variables for all variables +// declared on the impl declaration e.g., `impl for Box<[(A,B)]>` +// would return ($0, $1) where $0 and $1 are freshly instantiated type +// variables. +pub fn free_substs_for_impl<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>, + _span: Span, + impl_def_id: ast::DefId) + -> Substs<'tcx> +{ + let tcx = infcx.tcx; + let impl_generics = ty::lookup_item_type(tcx, impl_def_id).generics; + + let some_types = impl_generics.types.map(|def| { + ty::mk_param_from_def(tcx, def) + }); + + let some_regions = impl_generics.regions.map(|def| { + // FIXME. This destruction scope information is pretty darn + // bogus; after all, the impl might not even be in this crate! + // But given what we do in coherence, it is harmless enough + // for now I think. -nmatsakis + let extent = region::DestructionScopeData::new(ast::DUMMY_NODE_ID); + ty::free_region_from_def(extent, def) + }); + + Substs::new(some_types, some_regions) +} + impl<'tcx, N> fmt::Debug for VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "VtableImpl({:?})", self.impl_def_id) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 6e81d14d73cad..1123c9236312a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -58,7 +58,7 @@ use middle::subst::{self, ParamSpace, Subst, Substs, VecPerParamSpace}; use middle::traits; use middle::ty; use middle::ty_fold::{self, TypeFoldable, TypeFolder}; -use middle::ty_walk::TypeWalker; +use middle::ty_walk::{self, TypeWalker}; use util::ppaux::{note_and_explain_region, bound_region_ptr_to_string}; use util::ppaux::ty_to_string; use util::ppaux::{Repr, UserString}; @@ -89,7 +89,8 @@ use syntax::codemap::Span; use syntax::parse::token::{self, InternedString, special_idents}; use syntax::print::pprust; use syntax::ptr::P; -use syntax::{ast, ast_map}; +use syntax::ast; +use syntax::ast_map::{self, LinkedPath}; pub type Disr = u64; @@ -261,7 +262,7 @@ pub struct field_ty { // Contains information needed to resolve types and (in the future) look up // the types of AST nodes. -#[derive(Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct creader_cache_key { pub cnum: CrateNum, pub pos: usize, @@ -595,7 +596,7 @@ pub type ObjectCastMap<'tcx> = RefCell>>; /// will push one or more such restriction into the /// `transmute_restrictions` vector during `intrinsicck`. They are /// then checked during `trans` by the fn `check_intrinsics`. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct TransmuteRestriction<'tcx> { /// The span whence the restriction comes. pub span: Span, @@ -885,7 +886,7 @@ macro_rules! sty_debug_print { // variable names. mod inner { use middle::ty; - #[derive(Copy)] + #[derive(Copy, Clone)] struct DebugStat { total: usize, region_infer: usize, @@ -3167,21 +3168,11 @@ impl<'tcx> TyS<'tcx> { TypeWalker::new(self) } - /// Iterator that walks types reachable from `self`, in - /// depth-first order. Note that this is a shallow walk. For - /// example: - /// - /// ```notrust - /// isize => { } - /// Foo> => { Bar, isize } - /// [isize] => { isize } - /// ``` - pub fn walk_children(&'tcx self) -> TypeWalker<'tcx> { - // Walks type reachable from `self` but not `self - let mut walker = self.walk(); - let r = walker.next(); - assert_eq!(r, Some(self)); - walker + /// Iterator that walks the immediate children of `self`. Hence + /// `Foo, u32>` yields the sequence `[Bar, u32]` + /// (but not `i32`, like `walk`). + pub fn walk_shallow(&'tcx self) -> IntoIter> { + ty_walk::walk_shallow(self) } pub fn as_opt_param_ty(&self) -> Option { @@ -4012,7 +4003,7 @@ pub fn is_instantiable<'tcx>(cx: &ctxt<'tcx>, r_ty: Ty<'tcx>) -> bool { /// /// The ordering of the cases is significant. They are sorted so that cmp::max /// will keep the "more erroneous" of two values. -#[derive(Copy, PartialOrd, Ord, Eq, PartialEq, Debug)] +#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] pub enum Representability { Representable, ContainsRecursive, @@ -4743,7 +4734,7 @@ pub fn expr_is_lval(tcx: &ctxt, e: &ast::Expr) -> bool { /// two kinds of rvalues is an artifact of trans which reflects how we will /// generate code for that kind of expression. See trans/expr.rs for more /// information. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum ExprKind { LvalueExpr, RvalueDpsExpr, @@ -5439,7 +5430,7 @@ pub fn item_path_str(cx: &ctxt, id: ast::DefId) -> String { with_path(cx, id, |path| ast_map::path_to_string(path)).to_string() } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum DtorKind { NoDtor, TraitDtor(DefId, bool) @@ -5484,7 +5475,7 @@ pub fn with_path(cx: &ctxt, id: ast::DefId, f: F) -> T where if id.krate == ast::LOCAL_CRATE { cx.map.with_path(id.node, f) } else { - f(csearch::get_item_path(cx, id).iter().cloned().chain(None)) + f(csearch::get_item_path(cx, id).iter().cloned().chain(LinkedPath::empty())) } } @@ -7163,7 +7154,7 @@ pub fn make_substs_for_receiver_types<'tcx>(tcx: &ty::ctxt<'tcx>, trait_ref.substs.clone().with_method(meth_tps, meth_regions) } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum CopyImplementationError { FieldDoesNotImplementCopy(ast::Name), VariantDoesNotImplementCopy(ast::Name), diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index f17ba78007bb2..5f77574f65ed4 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -39,6 +39,8 @@ use middle::subst::VecPerParamSpace; use middle::ty::{self, Ty}; use middle::traits; use std::rc::Rc; +use syntax::abi; +use syntax::ast; use syntax::owned_slice::OwnedSlice; use util::ppaux::Repr; @@ -47,7 +49,7 @@ use util::ppaux::Repr; /// The TypeFoldable trait is implemented for every type that can be folded. /// Basically, every type that has a corresponding method in TypeFolder. -pub trait TypeFoldable<'tcx> { +pub trait TypeFoldable<'tcx>: Repr<'tcx> + Clone { fn fold_with>(&self, folder: &mut F) -> Self; } @@ -149,12 +151,20 @@ pub trait TypeFolder<'tcx> : Sized { // can easily refactor the folding into the TypeFolder trait as // needed. -impl<'tcx> TypeFoldable<'tcx> for () { - fn fold_with>(&self, _: &mut F) -> () { - () +macro_rules! CopyImpls { + ($($ty:ty),+) => { + $( + impl<'tcx> TypeFoldable<'tcx> for $ty { + fn fold_with>(&self, _: &mut F) -> $ty { + *self + } + } + )+ } } +CopyImpls! { (), ast::Unsafety, abi::Abi } + impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { fn fold_with>(&self, folder: &mut F) -> (T, U) { (self.0.fold_with(folder), self.1.fold_with(folder)) diff --git a/src/librustc/middle/ty_match.rs b/src/librustc/middle/ty_match.rs new file mode 100644 index 0000000000000..bb00fadc39c95 --- /dev/null +++ b/src/librustc/middle/ty_match.rs @@ -0,0 +1,95 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use middle::ty::{self, Ty}; +use middle::ty_relate::{self, Relate, TypeRelation, RelateResult}; +use util::ppaux::Repr; + +/// A type "A" *matches* "B" if the fresh types in B could be +/// substituted with values so as to make it equal to A. Matching is +/// intended to be used only on freshened types, and it basically +/// indicates if the non-freshened versions of A and B could have been +/// unified. +/// +/// It is only an approximation. If it yields false, unification would +/// definitely fail, but a true result doesn't mean unification would +/// succeed. This is because we don't track the "side-constraints" on +/// type variables, nor do we track if the same freshened type appears +/// more than once. To some extent these approximations could be +/// fixed, given effort. +/// +/// Like subtyping, matching is really a binary relation, so the only +/// important thing about the result is Ok/Err. Also, matching never +/// affects any type variables or unification state. +pub struct Match<'a, 'tcx: 'a> { + tcx: &'a ty::ctxt<'tcx> +} + +impl<'a, 'tcx> Match<'a, 'tcx> { + pub fn new(tcx: &'a ty::ctxt<'tcx>) -> Match<'a, 'tcx> { + Match { tcx: tcx } + } +} + +impl<'a, 'tcx> TypeRelation<'a, 'tcx> for Match<'a, 'tcx> { + fn tag(&self) -> &'static str { "Match" } + fn tcx(&self) -> &'a ty::ctxt<'tcx> { self.tcx } + fn a_is_expected(&self) -> bool { true } // irrelevant + + fn relate_with_variance>(&mut self, + _: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T> + { + self.relate(a, b) + } + + fn regions(&mut self, a: ty::Region, b: ty::Region) -> RelateResult<'tcx, ty::Region> { + debug!("{}.regions({}, {})", + self.tag(), + a.repr(self.tcx()), + b.repr(self.tcx())); + Ok(a) + } + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug!("{}.tys({}, {})", self.tag(), + a.repr(self.tcx()), b.repr(self.tcx())); + if a == b { return Ok(a); } + + match (&a.sty, &b.sty) { + (_, &ty::ty_infer(ty::FreshTy(_))) | + (_, &ty::ty_infer(ty::FreshIntTy(_))) => { + Ok(a) + } + + (&ty::ty_infer(_), _) | + (_, &ty::ty_infer(_)) => { + Err(ty::terr_sorts(ty_relate::expected_found(self, &a, &b))) + } + + (&ty::ty_err, _) | (_, &ty::ty_err) => { + Ok(self.tcx().types.err) + } + + _ => { + ty_relate::super_relate_tys(self, a, b) + } + } + } + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx> + { + Ok(ty::Binder(try!(self.relate(a.skip_binder(), b.skip_binder())))) + } +} diff --git a/src/librustc/middle/ty_relate/mod.rs b/src/librustc/middle/ty_relate/mod.rs new file mode 100644 index 0000000000000..1205b7d957930 --- /dev/null +++ b/src/librustc/middle/ty_relate/mod.rs @@ -0,0 +1,655 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Generalized type relating mechanism. A type relation R relates a +//! pair of values (A, B). A and B are usually types or regions but +//! can be other things. Examples of type relations are subtyping, +//! type equality, etc. + +use middle::subst::{ErasedRegions, NonerasedRegions, ParamSpace, Substs}; +use middle::ty::{self, Ty}; +use middle::ty_fold::TypeFoldable; +use std::rc::Rc; +use syntax::abi; +use syntax::ast; +use util::ppaux::Repr; + +pub type RelateResult<'tcx, T> = Result>; + +pub trait TypeRelation<'a,'tcx> : Sized { + fn tcx(&self) -> &'a ty::ctxt<'tcx>; + + /// Returns a static string we can use for printouts. + fn tag(&self) -> &'static str; + + /// Returns true if the value `a` is the "expected" type in the + /// relation. Just affects error messages. + fn a_is_expected(&self) -> bool; + + /// Generic relation routine suitable for most anything. + fn relate>(&mut self, a: &T, b: &T) -> RelateResult<'tcx, T> { + Relate::relate(self, a, b) + } + + /// Switch variance for the purpose of relating `a` and `b`. + fn relate_with_variance>(&mut self, + variance: ty::Variance, + a: &T, + b: &T) + -> RelateResult<'tcx, T>; + + // Overrideable relations. You shouldn't typically call these + // directly, instead call `relate()`, which in turn calls + // these. This is both more uniform but also allows us to add + // additional hooks for other types in the future if needed + // without making older code, which called `relate`, obsolete. + + fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>>; + + fn regions(&mut self, a: ty::Region, b: ty::Region) + -> RelateResult<'tcx, ty::Region>; + + fn binders(&mut self, a: &ty::Binder, b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where T: Relate<'a,'tcx>; +} + +pub trait Relate<'a,'tcx>: TypeFoldable<'tcx> { + fn relate>(relation: &mut R, + a: &Self, + b: &Self) + -> RelateResult<'tcx, Self>; +} + +/////////////////////////////////////////////////////////////////////////// +// Relate impls + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::mt<'tcx> { + fn relate(relation: &mut R, + a: &ty::mt<'tcx>, + b: &ty::mt<'tcx>) + -> RelateResult<'tcx, ty::mt<'tcx>> + where R: TypeRelation<'a,'tcx> + { + debug!("{}.mts({}, {})", + relation.tag(), + a.repr(relation.tcx()), + b.repr(relation.tcx())); + if a.mutbl != b.mutbl { + Err(ty::terr_mutability) + } else { + let mutbl = a.mutbl; + let variance = match mutbl { + ast::MutImmutable => ty::Covariant, + ast::MutMutable => ty::Invariant, + }; + let ty = try!(relation.relate_with_variance(variance, &a.ty, &b.ty)); + Ok(ty::mt {ty: ty, mutbl: mutbl}) + } + } +} + +// substitutions are not themselves relatable without more context, +// but they is an important subroutine for things that ARE relatable, +// like traits etc. +fn relate_item_substs<'a,'tcx:'a,R>(relation: &mut R, + item_def_id: ast::DefId, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + debug!("substs: item_def_id={} a_subst={} b_subst={}", + item_def_id.repr(relation.tcx()), + a_subst.repr(relation.tcx()), + b_subst.repr(relation.tcx())); + + let variances; + let opt_variances = if relation.tcx().variance_computed.get() { + variances = ty::item_variances(relation.tcx(), item_def_id); + Some(&*variances) + } else { + None + }; + relate_substs(relation, opt_variances, a_subst, b_subst) +} + +fn relate_substs<'a,'tcx,R>(relation: &mut R, + variances: Option<&ty::ItemVariances>, + a_subst: &Substs<'tcx>, + b_subst: &Substs<'tcx>) + -> RelateResult<'tcx, Substs<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let mut substs = Substs::empty(); + + for &space in &ParamSpace::all() { + let a_tps = a_subst.types.get_slice(space); + let b_tps = b_subst.types.get_slice(space); + let t_variances = variances.map(|v| v.types.get_slice(space)); + let tps = try!(relate_type_params(relation, t_variances, a_tps, b_tps)); + substs.types.replace(space, tps); + } + + match (&a_subst.regions, &b_subst.regions) { + (&ErasedRegions, _) | (_, &ErasedRegions) => { + substs.regions = ErasedRegions; + } + + (&NonerasedRegions(ref a), &NonerasedRegions(ref b)) => { + for &space in &ParamSpace::all() { + let a_regions = a.get_slice(space); + let b_regions = b.get_slice(space); + let r_variances = variances.map(|v| v.regions.get_slice(space)); + let regions = try!(relate_region_params(relation, + r_variances, + a_regions, + b_regions)); + substs.mut_regions().replace(space, regions); + } + } + } + + Ok(substs) +} + +fn relate_type_params<'a,'tcx,R>(relation: &mut R, + variances: Option<&[ty::Variance]>, + a_tys: &[Ty<'tcx>], + b_tys: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> +{ + if a_tys.len() != b_tys.len() { + return Err(ty::terr_ty_param_size(expected_found(relation, + &a_tys.len(), + &b_tys.len()))); + } + + (0 .. a_tys.len()) + .map(|i| { + let a_ty = a_tys[i]; + let b_ty = b_tys[i]; + let v = variances.map_or(ty::Invariant, |v| v[i]); + relation.relate_with_variance(v, &a_ty, &b_ty) + }) + .collect() +} + +fn relate_region_params<'a,'tcx:'a,R>(relation: &mut R, + variances: Option<&[ty::Variance]>, + a_rs: &[ty::Region], + b_rs: &[ty::Region]) + -> RelateResult<'tcx, Vec> + where R: TypeRelation<'a,'tcx> +{ + let tcx = relation.tcx(); + let num_region_params = a_rs.len(); + + debug!("relate_region_params(a_rs={}, \ + b_rs={}, variances={})", + a_rs.repr(tcx), + b_rs.repr(tcx), + variances.repr(tcx)); + + assert_eq!(num_region_params, + variances.map_or(num_region_params, + |v| v.len())); + + assert_eq!(num_region_params, b_rs.len()); + + (0..a_rs.len()) + .map(|i| { + let a_r = a_rs[i]; + let b_r = b_rs[i]; + let variance = variances.map_or(ty::Invariant, |v| v[i]); + relation.relate_with_variance(variance, &a_r, &b_r) + }) + .collect() +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BareFnTy<'tcx> { + fn relate(relation: &mut R, + a: &ty::BareFnTy<'tcx>, + b: &ty::BareFnTy<'tcx>) + -> RelateResult<'tcx, ty::BareFnTy<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let unsafety = try!(relation.relate(&a.unsafety, &b.unsafety)); + let abi = try!(relation.relate(&a.abi, &b.abi)); + let sig = try!(relation.relate(&a.sig, &b.sig)); + Ok(ty::BareFnTy {unsafety: unsafety, + abi: abi, + sig: sig}) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::FnSig<'tcx> { + fn relate(relation: &mut R, + a: &ty::FnSig<'tcx>, + b: &ty::FnSig<'tcx>) + -> RelateResult<'tcx, ty::FnSig<'tcx>> + where R: TypeRelation<'a,'tcx> + { + if a.variadic != b.variadic { + return Err(ty::terr_variadic_mismatch( + expected_found(relation, &a.variadic, &b.variadic))); + } + + let inputs = try!(relate_arg_vecs(relation, + &a.inputs, + &b.inputs)); + + let output = try!(match (a.output, b.output) { + (ty::FnConverging(a_ty), ty::FnConverging(b_ty)) => + Ok(ty::FnConverging(try!(relation.relate(&a_ty, &b_ty)))), + (ty::FnDiverging, ty::FnDiverging) => + Ok(ty::FnDiverging), + (a, b) => + Err(ty::terr_convergence_mismatch( + expected_found(relation, &(a != ty::FnDiverging), &(b != ty::FnDiverging)))), + }); + + return Ok(ty::FnSig {inputs: inputs, + output: output, + variadic: a.variadic}); + } +} + +fn relate_arg_vecs<'a,'tcx,R>(relation: &mut R, + a_args: &[Ty<'tcx>], + b_args: &[Ty<'tcx>]) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> +{ + if a_args.len() != b_args.len() { + return Err(ty::terr_arg_count); + } + + a_args.iter() + .zip(b_args.iter()) + .map(|(a, b)| relation.relate_with_variance(ty::Contravariant, a, b)) + .collect() +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ast::Unsafety { + fn relate(relation: &mut R, + a: &ast::Unsafety, + b: &ast::Unsafety) + -> RelateResult<'tcx, ast::Unsafety> + where R: TypeRelation<'a,'tcx> + { + if a != b { + Err(ty::terr_unsafety_mismatch(expected_found(relation, a, b))) + } else { + Ok(*a) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for abi::Abi { + fn relate(relation: &mut R, + a: &abi::Abi, + b: &abi::Abi) + -> RelateResult<'tcx, abi::Abi> + where R: TypeRelation<'a,'tcx> + { + if a == b { + Ok(*a) + } else { + Err(ty::terr_abi_mismatch(expected_found(relation, a, b))) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionTy<'tcx> { + fn relate(relation: &mut R, + a: &ty::ProjectionTy<'tcx>, + b: &ty::ProjectionTy<'tcx>) + -> RelateResult<'tcx, ty::ProjectionTy<'tcx>> + where R: TypeRelation<'a,'tcx> + { + if a.item_name != b.item_name { + Err(ty::terr_projection_name_mismatched( + expected_found(relation, &a.item_name, &b.item_name))) + } else { + let trait_ref = try!(relation.relate(&*a.trait_ref, &*b.trait_ref)); + Ok(ty::ProjectionTy { trait_ref: Rc::new(trait_ref), item_name: a.item_name }) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ProjectionPredicate<'tcx> { + fn relate(relation: &mut R, + a: &ty::ProjectionPredicate<'tcx>, + b: &ty::ProjectionPredicate<'tcx>) + -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let projection_ty = try!(relation.relate(&a.projection_ty, &b.projection_ty)); + let ty = try!(relation.relate(&a.ty, &b.ty)); + Ok(ty::ProjectionPredicate { projection_ty: projection_ty, ty: ty }) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for Vec> { + fn relate(relation: &mut R, + a: &Vec>, + b: &Vec>) + -> RelateResult<'tcx, Vec>> + where R: TypeRelation<'a,'tcx> + { + // To be compatible, `a` and `b` must be for precisely the + // same set of traits and item names. We always require that + // projection bounds lists are sorted by trait-def-id and item-name, + // so we can just iterate through the lists pairwise, so long as they are the + // same length. + if a.len() != b.len() { + Err(ty::terr_projection_bounds_length(expected_found(relation, &a.len(), &b.len()))) + } else { + a.iter() + .zip(b.iter()) + .map(|(a, b)| relation.relate(a, b)) + .collect() + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::ExistentialBounds<'tcx> { + fn relate(relation: &mut R, + a: &ty::ExistentialBounds<'tcx>, + b: &ty::ExistentialBounds<'tcx>) + -> RelateResult<'tcx, ty::ExistentialBounds<'tcx>> + where R: TypeRelation<'a,'tcx> + { + let r = try!(relation.relate_with_variance(ty::Contravariant, + &a.region_bound, + &b.region_bound)); + let nb = try!(relation.relate(&a.builtin_bounds, &b.builtin_bounds)); + let pb = try!(relation.relate(&a.projection_bounds, &b.projection_bounds)); + Ok(ty::ExistentialBounds { region_bound: r, + builtin_bounds: nb, + projection_bounds: pb }) + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::BuiltinBounds { + fn relate(relation: &mut R, + a: &ty::BuiltinBounds, + b: &ty::BuiltinBounds) + -> RelateResult<'tcx, ty::BuiltinBounds> + where R: TypeRelation<'a,'tcx> + { + // Two sets of builtin bounds are only relatable if they are + // precisely the same (but see the coercion code). + if a != b { + Err(ty::terr_builtin_bounds(expected_found(relation, a, b))) + } else { + Ok(*a) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::TraitRef<'tcx> { + fn relate(relation: &mut R, + a: &ty::TraitRef<'tcx>, + b: &ty::TraitRef<'tcx>) + -> RelateResult<'tcx, ty::TraitRef<'tcx>> + where R: TypeRelation<'a,'tcx> + { + // Different traits cannot be related + if a.def_id != b.def_id { + Err(ty::terr_traits(expected_found(relation, &a.def_id, &b.def_id))) + } else { + let substs = try!(relate_item_substs(relation, a.def_id, a.substs, b.substs)); + Ok(ty::TraitRef { def_id: a.def_id, substs: relation.tcx().mk_substs(substs) }) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for Ty<'tcx> { + fn relate(relation: &mut R, + a: &Ty<'tcx>, + b: &Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> + { + relation.tys(a, b) + } +} + +/// The main "type relation" routine. Note that this does not handle +/// inference artifacts, so you should filter those out before calling +/// it. +pub fn super_relate_tys<'a,'tcx:'a,R>(relation: &mut R, + a: Ty<'tcx>, + b: Ty<'tcx>) + -> RelateResult<'tcx, Ty<'tcx>> + where R: TypeRelation<'a,'tcx> +{ + let tcx = relation.tcx(); + let a_sty = &a.sty; + let b_sty = &b.sty; + debug!("super_tys: a_sty={:?} b_sty={:?}", a_sty, b_sty); + match (a_sty, b_sty) { + (&ty::ty_infer(_), _) | + (_, &ty::ty_infer(_)) => + { + // The caller should handle these cases! + tcx.sess.bug("var types encountered in super_relate_tys") + } + + (&ty::ty_err, _) | (_, &ty::ty_err) => + { + Ok(tcx.types.err) + } + + (&ty::ty_char, _) | + (&ty::ty_bool, _) | + (&ty::ty_int(_), _) | + (&ty::ty_uint(_), _) | + (&ty::ty_float(_), _) | + (&ty::ty_str, _) + if a == b => + { + Ok(a) + } + + (&ty::ty_param(ref a_p), &ty::ty_param(ref b_p)) + if a_p.idx == b_p.idx && a_p.space == b_p.space => + { + Ok(a) + } + + (&ty::ty_enum(a_id, a_substs), &ty::ty_enum(b_id, b_substs)) + if a_id == b_id => + { + let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); + Ok(ty::mk_enum(tcx, a_id, tcx.mk_substs(substs))) + } + + (&ty::ty_trait(ref a_), &ty::ty_trait(ref b_)) => + { + let principal = try!(relation.relate(&a_.principal, &b_.principal)); + let bounds = try!(relation.relate(&a_.bounds, &b_.bounds)); + Ok(ty::mk_trait(tcx, principal, bounds)) + } + + (&ty::ty_struct(a_id, a_substs), &ty::ty_struct(b_id, b_substs)) + if a_id == b_id => + { + let substs = try!(relate_item_substs(relation, a_id, a_substs, b_substs)); + Ok(ty::mk_struct(tcx, a_id, tcx.mk_substs(substs))) + } + + (&ty::ty_closure(a_id, a_substs), + &ty::ty_closure(b_id, b_substs)) + if a_id == b_id => + { + // All ty_closure types with the same id represent + // the (anonymous) type of the same closure expression. So + // all of their regions should be equated. + let substs = try!(relate_substs(relation, None, a_substs, b_substs)); + Ok(ty::mk_closure(tcx, a_id, tcx.mk_substs(substs))) + } + + (&ty::ty_uniq(a_inner), &ty::ty_uniq(b_inner)) => + { + let typ = try!(relation.relate(&a_inner, &b_inner)); + Ok(ty::mk_uniq(tcx, typ)) + } + + (&ty::ty_ptr(ref a_mt), &ty::ty_ptr(ref b_mt)) => + { + let mt = try!(relation.relate(a_mt, b_mt)); + Ok(ty::mk_ptr(tcx, mt)) + } + + (&ty::ty_rptr(a_r, ref a_mt), &ty::ty_rptr(b_r, ref b_mt)) => + { + let r = try!(relation.relate_with_variance(ty::Contravariant, a_r, b_r)); + let mt = try!(relation.relate(a_mt, b_mt)); + Ok(ty::mk_rptr(tcx, tcx.mk_region(r), mt)) + } + + (&ty::ty_vec(a_t, Some(sz_a)), &ty::ty_vec(b_t, Some(sz_b))) => + { + let t = try!(relation.relate(&a_t, &b_t)); + if sz_a == sz_b { + Ok(ty::mk_vec(tcx, t, Some(sz_a))) + } else { + Err(ty::terr_fixed_array_size(expected_found(relation, &sz_a, &sz_b))) + } + } + + (&ty::ty_vec(a_t, None), &ty::ty_vec(b_t, None)) => + { + let t = try!(relation.relate(&a_t, &b_t)); + Ok(ty::mk_vec(tcx, t, None)) + } + + (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => + { + if as_.len() == bs.len() { + let ts = try!(as_.iter() + .zip(bs.iter()) + .map(|(a, b)| relation.relate(a, b)) + .collect::>()); + Ok(ty::mk_tup(tcx, ts)) + } else if as_.len() != 0 && bs.len() != 0 { + Err(ty::terr_tuple_size( + expected_found(relation, &as_.len(), &bs.len()))) + } else { + Err(ty::terr_sorts(expected_found(relation, &a, &b))) + } + } + + (&ty::ty_bare_fn(a_opt_def_id, a_fty), &ty::ty_bare_fn(b_opt_def_id, b_fty)) + if a_opt_def_id == b_opt_def_id => + { + let fty = try!(relation.relate(a_fty, b_fty)); + Ok(ty::mk_bare_fn(tcx, a_opt_def_id, tcx.mk_bare_fn(fty))) + } + + (&ty::ty_projection(ref a_data), &ty::ty_projection(ref b_data)) => + { + let projection_ty = try!(relation.relate(a_data, b_data)); + Ok(ty::mk_projection(tcx, projection_ty.trait_ref, projection_ty.item_name)) + } + + _ => + { + Err(ty::terr_sorts(expected_found(relation, &a, &b))) + } + } +} + +impl<'a,'tcx:'a> Relate<'a,'tcx> for ty::Region { + fn relate(relation: &mut R, + a: &ty::Region, + b: &ty::Region) + -> RelateResult<'tcx, ty::Region> + where R: TypeRelation<'a,'tcx> + { + relation.regions(*a, *b) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for ty::Binder + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &ty::Binder, + b: &ty::Binder) + -> RelateResult<'tcx, ty::Binder> + where R: TypeRelation<'a,'tcx> + { + relation.binders(a, b) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Rc + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Rc, + b: &Rc) + -> RelateResult<'tcx, Rc> + where R: TypeRelation<'a,'tcx> + { + let a: &T = a; + let b: &T = b; + Ok(Rc::new(try!(relation.relate(a, b)))) + } +} + +impl<'a,'tcx:'a,T> Relate<'a,'tcx> for Box + where T: Relate<'a,'tcx> +{ + fn relate(relation: &mut R, + a: &Box, + b: &Box) + -> RelateResult<'tcx, Box> + where R: TypeRelation<'a,'tcx> + { + let a: &T = a; + let b: &T = b; + Ok(Box::new(try!(relation.relate(a, b)))) + } +} + +/////////////////////////////////////////////////////////////////////////// +// Error handling + +pub fn expected_found<'a,'tcx,R,T>(relation: &mut R, + a: &T, + b: &T) + -> ty::expected_found + where R: TypeRelation<'a,'tcx>, T: Clone +{ + expected_found_bool(relation.a_is_expected(), a, b) +} + +pub fn expected_found_bool(a_is_expected: bool, + a: &T, + b: &T) + -> ty::expected_found + where T: Clone +{ + let a = a.clone(); + let b = b.clone(); + if a_is_expected { + ty::expected_found {expected: a, found: b} + } else { + ty::expected_found {expected: b, found: a} + } +} + diff --git a/src/librustc/middle/ty_walk.rs b/src/librustc/middle/ty_walk.rs index 5d492f1c95e11..ec09d6dcc1ee2 100644 --- a/src/librustc/middle/ty_walk.rs +++ b/src/librustc/middle/ty_walk.rs @@ -12,6 +12,7 @@ use middle::ty::{self, Ty}; use std::iter::Iterator; +use std::vec::IntoIter; pub struct TypeWalker<'tcx> { stack: Vec>, @@ -23,60 +24,6 @@ impl<'tcx> TypeWalker<'tcx> { TypeWalker { stack: vec!(ty), last_subtree: 1, } } - fn push_subtypes(&mut self, parent_ty: Ty<'tcx>) { - match parent_ty.sty { - ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | - ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => { - } - ty::ty_uniq(ty) | ty::ty_vec(ty, _) => { - self.stack.push(ty); - } - ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { - self.stack.push(mt.ty); - } - ty::ty_projection(ref data) => { - self.push_reversed(data.trait_ref.substs.types.as_slice()); - } - ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { - self.push_reversed(principal.substs().types.as_slice()); - self.push_reversed(&bounds.projection_bounds.iter().map(|pred| { - pred.0.ty - }).collect::>()); - } - ty::ty_enum(_, ref substs) | - ty::ty_struct(_, ref substs) | - ty::ty_closure(_, ref substs) => { - self.push_reversed(substs.types.as_slice()); - } - ty::ty_tup(ref ts) => { - self.push_reversed(ts); - } - ty::ty_bare_fn(_, ref ft) => { - self.push_sig_subtypes(&ft.sig); - } - } - } - - fn push_sig_subtypes(&mut self, sig: &ty::PolyFnSig<'tcx>) { - match sig.0.output { - ty::FnConverging(output) => { self.stack.push(output); } - ty::FnDiverging => { } - } - self.push_reversed(&sig.0.inputs); - } - - fn push_reversed(&mut self, tys: &[Ty<'tcx>]) { - // We push slices on the stack in reverse order so as to - // maintain a pre-order traversal. As of the time of this - // writing, the fact that the traversal is pre-order is not - // known to be significant to any code, but it seems like the - // natural order one would expect (basically, the order of the - // types as they are written). - for &ty in tys.iter().rev() { - self.stack.push(ty); - } - } - /// Skips the subtree of types corresponding to the last type /// returned by `next()`. /// @@ -105,10 +52,70 @@ impl<'tcx> Iterator for TypeWalker<'tcx> { } Some(ty) => { self.last_subtree = self.stack.len(); - self.push_subtypes(ty); + push_subtypes(&mut self.stack, ty); debug!("next: stack={:?}", self.stack); Some(ty) } } } } + +pub fn walk_shallow<'tcx>(ty: Ty<'tcx>) -> IntoIter> { + let mut stack = vec![]; + push_subtypes(&mut stack, ty); + stack.into_iter() +} + +fn push_subtypes<'tcx>(stack: &mut Vec>, parent_ty: Ty<'tcx>) { + match parent_ty.sty { + ty::ty_bool | ty::ty_char | ty::ty_int(_) | ty::ty_uint(_) | ty::ty_float(_) | + ty::ty_str | ty::ty_infer(_) | ty::ty_param(_) | ty::ty_err => { + } + ty::ty_uniq(ty) | ty::ty_vec(ty, _) => { + stack.push(ty); + } + ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => { + stack.push(mt.ty); + } + ty::ty_projection(ref data) => { + push_reversed(stack, data.trait_ref.substs.types.as_slice()); + } + ty::ty_trait(box ty::TyTrait { ref principal, ref bounds }) => { + push_reversed(stack, principal.substs().types.as_slice()); + push_reversed(stack, &bounds.projection_bounds.iter().map(|pred| { + pred.0.ty + }).collect::>()); + } + ty::ty_enum(_, ref substs) | + ty::ty_struct(_, ref substs) | + ty::ty_closure(_, ref substs) => { + push_reversed(stack, substs.types.as_slice()); + } + ty::ty_tup(ref ts) => { + push_reversed(stack, ts); + } + ty::ty_bare_fn(_, ref ft) => { + push_sig_subtypes(stack, &ft.sig); + } + } +} + +fn push_sig_subtypes<'tcx>(stack: &mut Vec>, sig: &ty::PolyFnSig<'tcx>) { + match sig.0.output { + ty::FnConverging(output) => { stack.push(output); } + ty::FnDiverging => { } + } + push_reversed(stack, &sig.0.inputs); +} + +fn push_reversed<'tcx>(stack: &mut Vec>, tys: &[Ty<'tcx>]) { + // We push slices on the stack in reverse order so as to + // maintain a pre-order traversal. As of the time of this + // writing, the fact that the traversal is pre-order is not + // known to be significant to any code, but it seems like the + // natural order one would expect (basically, the order of the + // types as they are written). + for &ty in tys.iter().rev() { + stack.push(ty); + } +} diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index c67819ab7e3c4..a7d608d2c879c 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -247,7 +247,7 @@ pub fn basic_options() -> Options { // users can have their own entry // functions that don't start a // scheduler -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum EntryFnType { EntryMain, EntryStart, @@ -304,7 +304,7 @@ macro_rules! options { { let mut op = $defaultfn(); for option in matches.opt_strs($prefix) { - let mut iter = option.splitn(1, '='); + let mut iter = option.splitn(2, '='); let key = iter.next().unwrap(); let value = iter.next(); let option_to_lookup = key.replace("-", "_"); @@ -958,7 +958,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { } let libs = matches.opt_strs("l").into_iter().map(|s| { - let mut parts = s.splitn(1, '='); + let mut parts = s.splitn(2, '='); let kind = parts.next().unwrap(); let (name, kind) = match (parts.next(), kind) { (None, name) | @@ -1010,7 +1010,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let mut externs = HashMap::new(); for arg in &matches.opt_strs("extern") { - let mut parts = arg.splitn(1, '='); + let mut parts = arg.splitn(2, '='); let name = match parts.next() { Some(s) => s, None => early_error("--extern value must not be empty"), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 452589a240754..60b422b3769d5 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -384,13 +384,7 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String { } ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty), ty_err => "[type error]".to_string(), - ty_param(ref param_ty) => { - if cx.sess.verbose() { - param_ty.repr(cx) - } else { - param_ty.user_string(cx) - } - } + ty_param(ref param_ty) => param_ty.user_string(cx), ty_enum(did, substs) | ty_struct(did, substs) => { let base = ty::item_path_str(cx, did); parameterized(cx, &base, substs, did, &[], @@ -1532,3 +1526,9 @@ impl<'tcx> UserString<'tcx> for ty::Predicate<'tcx> { } } } + +impl<'tcx> Repr<'tcx> for ast::Unsafety { + fn repr(&self, _: &ctxt<'tcx>) -> String { + format!("{:?}", *self) + } +} diff --git a/src/librustc_back/target/apple_ios_base.rs b/src/librustc_back/target/apple_ios_base.rs index 42cbdd7577d8e..7dcd6ba6cd11f 100644 --- a/src/librustc_back/target/apple_ios_base.rs +++ b/src/librustc_back/target/apple_ios_base.rs @@ -15,7 +15,7 @@ use target::TargetOptions; use self::Arch::*; #[allow(non_camel_case_types)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Arch { Armv7, Armv7s, diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 268e469b7f915..f8da075e4bdc2 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -334,7 +334,7 @@ impl ToInteriorKind for mc::InteriorKind { } } -#[derive(Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum LoanPathElem { LpDeref(mc::PointerKind), // `*LV` in README.md LpInterior(InteriorKind), // `LV.f` in README.md @@ -500,13 +500,13 @@ pub struct BckError<'tcx> { code: bckerr_code } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum AliasableViolationKind { MutabilityViolation, BorrowViolation(euv::LoanCause) } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum MovedValueUseKind { MovedInUse, MovedInCapture, diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index a4470acbe4d20..2d1b57243d1cc 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -94,7 +94,7 @@ impl Clone for MovePathIndex { const InvalidMovePathIndex: MovePathIndex = MovePathIndex(usize::MAX); /// Index into `MoveData.moves`, used like a pointer -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub struct MoveIndex(usize); impl MoveIndex { @@ -125,7 +125,7 @@ pub struct MovePath<'tcx> { pub next_sibling: MovePathIndex, } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum MoveKind { Declared, // When declared, variables start out "moved". MoveExpr, // Expression or binding that moves a variable @@ -133,7 +133,7 @@ pub enum MoveKind { Captured // Closure creation that moves a value } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Move { /// Path being moved. pub path: MovePathIndex, @@ -148,7 +148,7 @@ pub struct Move { pub next_move: MoveIndex } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Assignment { /// Path being assigned. pub path: MovePathIndex, @@ -160,7 +160,7 @@ pub struct Assignment { pub span: Span, } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct VariantMatch { /// downcast to the variant. pub path: MovePathIndex, diff --git a/src/librustc_borrowck/graphviz.rs b/src/librustc_borrowck/graphviz.rs index fb8afa83d864d..ade52bfde35e6 100644 --- a/src/librustc_borrowck/graphviz.rs +++ b/src/librustc_borrowck/graphviz.rs @@ -26,7 +26,7 @@ use rustc::middle::dataflow; use std::rc::Rc; use std::borrow::IntoCow; -#[derive(Debug, Copy)] +#[derive(Debug, Copy, Clone)] pub enum Variant { Loans, Moves, diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index be416327dad3b..b32c6829a221b 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -182,7 +182,7 @@ fn make_input(free_matches: &[String]) -> Option<(Input, Option)> { } // Whether to stop or continue compilation. -#[derive(Copy, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Compilation { Stop, Continue, @@ -265,7 +265,7 @@ pub trait CompilerCalls<'a> { } // CompilerCalls instance for a regular rustc build. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct RustcDefaultCalls; impl<'a> CompilerCalls<'a> for RustcDefaultCalls { diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index fe55ca3b73bfb..410f31e0900c4 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -44,7 +44,7 @@ use std::option; use std::path::PathBuf; use std::str::FromStr; -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum PpSourceMode { PpmNormal, PpmEveryBodyLoops, @@ -56,7 +56,7 @@ pub enum PpSourceMode { } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum PpFlowGraphMode { Default, /// Drops the labels from the edges in the flowgraph output. This @@ -65,7 +65,7 @@ pub enum PpFlowGraphMode { /// have become a pain to maintain. UnlabelledEdges, } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum PpMode { PpmSource(PpSourceMode), PpmFlowGraph(PpFlowGraphMode), @@ -74,7 +74,7 @@ pub enum PpMode { pub fn parse_pretty(sess: &Session, name: &str, extended: bool) -> (PpMode, Option) { - let mut split = name.splitn(1, '='); + let mut split = name.splitn(2, '='); let first = split.next().unwrap(); let opt_second = split.next(); let first = match (first, extended) { @@ -226,6 +226,10 @@ impl<'ast> pprust::PpAnn for IdentifiedAnnotation<'ast> { try!(pp::space(&mut s.s)); s.synth_comment(item.id.to_string()) } + pprust::NodeSubItem(id) => { + try!(pp::space(&mut s.s)); + s.synth_comment(id.to_string()) + } pprust::NodeBlock(blk) => { try!(pp::space(&mut s.s)); s.synth_comment(format!("block {}", blk.id)) diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index ed4d30f300c78..f9be71561e384 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -22,7 +22,7 @@ use rustc_typeck::middle::stability; use rustc_typeck::middle::subst; use rustc_typeck::middle::subst::Subst; use rustc_typeck::middle::ty::{self, Ty}; -use rustc_typeck::middle::infer::combine::Combine; +use rustc_typeck::middle::ty_relate::TypeRelation; use rustc_typeck::middle::infer; use rustc_typeck::middle::infer::lub::Lub; use rustc_typeck::middle::infer::glb::Glb; @@ -350,21 +350,21 @@ impl<'a, 'tcx> Env<'a, 'tcx> { pub fn sub(&self) -> Sub<'a, 'tcx> { let trace = self.dummy_type_trace(); - Sub(self.infcx.combine_fields(true, trace)) + self.infcx.sub(true, trace) } pub fn lub(&self) -> Lub<'a, 'tcx> { let trace = self.dummy_type_trace(); - Lub(self.infcx.combine_fields(true, trace)) + self.infcx.lub(true, trace) } pub fn glb(&self) -> Glb<'a, 'tcx> { let trace = self.dummy_type_trace(); - Glb(self.infcx.combine_fields(true, trace)) + self.infcx.glb(true, trace) } pub fn make_lub_ty(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> Ty<'tcx> { - match self.lub().tys(t1, t2) { + match self.lub().relate(&t1, &t2) { Ok(t) => t, Err(ref e) => panic!("unexpected error computing LUB: {}", ty::type_err_to_str(self.infcx.tcx, e)) @@ -374,7 +374,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { /// Checks that `t1 <: t2` is true (this may register additional /// region checks). pub fn check_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { - match self.sub().tys(t1, t2) { + match self.sub().relate(&t1, &t2) { Ok(_) => { } Err(ref e) => { panic!("unexpected error computing sub({},{}): {}", @@ -388,7 +388,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { /// Checks that `t1 <: t2` is false (this may register additional /// region checks). pub fn check_not_sub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) { - match self.sub().tys(t1, t2) { + match self.sub().relate(&t1, &t2) { Err(_) => { } Ok(_) => { panic!("unexpected success computing sub({},{})", @@ -400,7 +400,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { /// Checks that `LUB(t1,t2) == t_lub` pub fn check_lub(&self, t1: Ty<'tcx>, t2: Ty<'tcx>, t_lub: Ty<'tcx>) { - match self.lub().tys(t1, t2) { + match self.lub().relate(&t1, &t2) { Ok(t) => { self.assert_eq(t, t_lub); } @@ -417,7 +417,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> { self.ty_to_string(t1), self.ty_to_string(t2), self.ty_to_string(t_glb)); - match self.glb().tys(t1, t2) { + match self.glb().relate(&t1, &t2) { Err(e) => { panic!("unexpected error computing LUB: {:?}", e) } diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index cc22f8ff809ef..3bb737ddc1279 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -63,7 +63,7 @@ declare_lint! { "suggest using `loop { }` instead of `while true { }`" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct WhileTrue; impl LintPass for WhileTrue { @@ -107,7 +107,7 @@ declare_lint! { "shift exceeds the type's number of bits" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct TypeLimits { /// Id of the last visited negated expression negated_expr_id: ast::NodeId, @@ -431,7 +431,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for ImproperCTypesVisitor<'a, 'tcx> { } } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct ImproperCTypes; impl LintPass for ImproperCTypes { @@ -474,7 +474,7 @@ declare_lint! { "use of owned (Box type) heap memory" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct BoxPointers; impl BoxPointers { @@ -621,7 +621,7 @@ declare_lint! { "detects attributes that were not used by the compiler" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnusedAttributes; impl LintPass for UnusedAttributes { @@ -662,7 +662,7 @@ declare_lint! { "path statements with no effect" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct PathStatements; impl LintPass for PathStatements { @@ -696,7 +696,7 @@ declare_lint! { "unused result of an expression in a statement" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnusedResults; impl LintPass for UnusedResults { @@ -764,7 +764,7 @@ declare_lint! { "types, variants, traits and type parameters should have camel case names" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct NonCamelCaseTypes; impl NonCamelCaseTypes { @@ -874,7 +874,7 @@ declare_lint! { "methods, functions, lifetime parameters and modules should have snake case names" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct NonSnakeCase; impl NonSnakeCase { @@ -1014,7 +1014,7 @@ declare_lint! { "static constants should have uppercase identifiers" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct NonUpperCaseGlobals; impl NonUpperCaseGlobals { @@ -1072,7 +1072,7 @@ declare_lint! { "`if`, `match`, `while` and `return` do not need parentheses" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnusedParens; impl UnusedParens { @@ -1166,7 +1166,7 @@ declare_lint! { "unnecessary braces around an imported item" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnusedImportBraces; impl LintPass for UnusedImportBraces { @@ -1196,7 +1196,7 @@ declare_lint! { "using `Struct { x: x }` instead of `Struct { x }`" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct NonShorthandFieldPatterns; impl LintPass for NonShorthandFieldPatterns { @@ -1233,7 +1233,7 @@ declare_lint! { "unnecessary use of an `unsafe` block" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnusedUnsafe; impl LintPass for UnusedUnsafe { @@ -1258,7 +1258,7 @@ declare_lint! { "usage of `unsafe` code" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnsafeCode; impl LintPass for UnsafeCode { @@ -1319,7 +1319,7 @@ declare_lint! { "detect mut variables which don't need to be mutable" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnusedMut; impl UnusedMut { @@ -1388,7 +1388,7 @@ declare_lint! { "detects unnecessary allocations that can be eliminated" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnusedAllocation; impl LintPass for UnusedAllocation { @@ -1625,7 +1625,7 @@ declare_lint! { "detects potentially-forgotten implementations of `Copy`" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct MissingCopyImplementations; impl LintPass for MissingCopyImplementations { @@ -1740,7 +1740,7 @@ declare_lint! { } /// Checks for use of items with `#[deprecated]` attributes -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Stability; impl Stability { @@ -1800,7 +1800,7 @@ declare_lint! { "functions that cannot return without calling themselves" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnconditionalRecursion; @@ -1991,7 +1991,7 @@ declare_lint! { "compiler plugin used as ordinary library in non-plugin crate" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct PluginAsLibrary; impl LintPass for PluginAsLibrary { @@ -2045,7 +2045,7 @@ declare_lint! { "const items will not have their symbols exported" } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct InvalidNoMangleItems; impl LintPass for InvalidNoMangleItems { @@ -2088,7 +2088,7 @@ impl LintPass for InvalidNoMangleItems { } /// Forbids using the `#[feature(...)]` attribute -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnstableFeatures; declare_lint! { diff --git a/src/librustc_llvm/diagnostic.rs b/src/librustc_llvm/diagnostic.rs index aca4d265bc963..e6350ae44d43f 100644 --- a/src/librustc_llvm/diagnostic.rs +++ b/src/librustc_llvm/diagnostic.rs @@ -18,7 +18,7 @@ use std::ptr; use {ValueRef, TwineRef, DebugLocRef, DiagnosticInfoRef}; -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum OptimizationDiagnosticKind { OptimizationRemark, OptimizationMissed, @@ -38,7 +38,7 @@ impl OptimizationDiagnosticKind { } #[allow(raw_pointer_derive)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct OptimizationDiagnostic { pub kind: OptimizationDiagnosticKind, pub pass_name: *const c_char, @@ -69,14 +69,13 @@ impl OptimizationDiagnostic { } } +#[derive(Copy, Clone)] pub struct InlineAsmDiagnostic { pub cookie: c_uint, pub message: TwineRef, pub instruction: ValueRef, } -impl Copy for InlineAsmDiagnostic {} - impl InlineAsmDiagnostic { unsafe fn unpack(di: DiagnosticInfoRef) -> InlineAsmDiagnostic { @@ -96,7 +95,7 @@ impl InlineAsmDiagnostic { } } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Diagnostic { Optimization(OptimizationDiagnostic), InlineAsm(InlineAsmDiagnostic), diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index cdafa4a16d07d..9b0ae2e9ef858 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -76,7 +76,7 @@ pub const False: Bool = 0 as Bool; // Consts for the LLVM CallConv type, pre-cast to usize. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum CallConv { CCallConv = 0, FastCallConv = 8, @@ -86,7 +86,7 @@ pub enum CallConv { X86_64_Win64 = 79, } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Visibility { LLVMDefaultVisibility = 0, HiddenVisibility = 1, @@ -97,7 +97,7 @@ pub enum Visibility { // DLLExportLinkage, GhostLinkage and LinkOnceODRAutoHideLinkage. // LinkerPrivateLinkage and LinkerPrivateWeakLinkage are not included either; // they've been removed in upstream LLVM commit r203866. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Linkage { ExternalLinkage = 0, AvailableExternallyLinkage = 1, @@ -113,7 +113,7 @@ pub enum Linkage { } #[repr(C)] -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum DiagnosticSeverity { Error, Warning, @@ -154,7 +154,7 @@ bitflags! { #[repr(u64)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum OtherAttribute { // The following are not really exposed in // the LLVM c api so instead to add these @@ -175,13 +175,13 @@ pub enum OtherAttribute { NonNullAttribute = 1 << 44, } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum SpecialAttribute { DereferenceableAttribute(u64) } #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum AttributeSet { ReturnIndex = 0, FunctionIndex = !0 @@ -273,7 +273,7 @@ impl AttrBuilder { } // enum for the LLVM IntPredicate type -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum IntPredicate { IntEQ = 32, IntNE = 33, @@ -288,7 +288,7 @@ pub enum IntPredicate { } // enum for the LLVM RealPredicate type -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum RealPredicate { RealPredicateFalse = 0, RealOEQ = 1, @@ -310,7 +310,7 @@ pub enum RealPredicate { // The LLVM TypeKind type - must stay in sync with the def of // LLVMTypeKind in llvm/include/llvm-c/Core.h -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] #[repr(C)] pub enum TypeKind { Void = 0, @@ -332,7 +332,7 @@ pub enum TypeKind { } #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum AtomicBinOp { AtomicXchg = 0, AtomicAdd = 1, @@ -348,7 +348,7 @@ pub enum AtomicBinOp { } #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum AtomicOrdering { NotAtomic = 0, Unordered = 1, @@ -362,13 +362,13 @@ pub enum AtomicOrdering { // Consts for the LLVMCodeGenFileType type (in include/llvm/c/TargetMachine.h) #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum FileType { AssemblyFileType = 0, ObjectFileType = 1 } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum MetadataType { MD_dbg = 0, MD_tbaa = 1, @@ -385,13 +385,13 @@ pub enum MetadataType { } // Inline Asm Dialect -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum AsmDialect { AD_ATT = 0, AD_Intel = 1 } -#[derive(Copy, PartialEq, Clone)] +#[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum CodeGenOptLevel { CodeGenLevelNone = 0, @@ -400,7 +400,7 @@ pub enum CodeGenOptLevel { CodeGenLevelAggressive = 3, } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum RelocMode { RelocDefault = 0, @@ -410,7 +410,7 @@ pub enum RelocMode { } #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum CodeGenModel { CodeModelDefault = 0, CodeModelJITDefault = 1, @@ -421,7 +421,7 @@ pub enum CodeGenModel { } #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum DiagnosticKind { DK_InlineAsm = 0, DK_StackSize, @@ -533,7 +533,7 @@ pub mod debuginfo { pub type DIEnumerator = DIDescriptor; pub type DITemplateTypeParameter = DIDescriptor; - #[derive(Copy)] + #[derive(Copy, Clone)] pub enum DIDescriptorFlags { FlagPrivate = 1 << 0, FlagProtected = 1 << 1, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 5bff5479e2ea3..52db6013f4d5d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -61,7 +61,7 @@ use std::rc::Rc; // Specifies how duplicates should be handled when adding a child item if // another item exists with the same name in some namespace. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum DuplicateCheckingMode { ForbidDuplicateModules, ForbidDuplicateTypesAndModules, @@ -70,7 +70,7 @@ enum DuplicateCheckingMode { OverwriteDuplicates } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum NamespaceError { NoError, ModuleError, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index ff635a6c46b22..045320e4fa425 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -107,7 +107,7 @@ mod record_exports; mod build_reduced_graph; mod resolve_imports; -#[derive(Copy)] +#[derive(Copy, Clone)] struct BindingInfo { span: Span, binding_mode: BindingMode, @@ -116,14 +116,14 @@ struct BindingInfo { // Map from the name in a pattern to its binding mode. type BindingMap = HashMap; -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum PatternBindingMode { RefutableMode, LocalIrrefutableMode, ArgumentIrrefutableMode, } -#[derive(Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] enum Namespace { TypeNS, ValueNS @@ -162,9 +162,12 @@ impl NamespaceResult { } enum NameDefinition { - NoNameDefinition, //< The name was unbound. - ChildNameDefinition(Def, LastPrivate), //< The name identifies an immediate child. - ImportNameDefinition(Def, LastPrivate) //< The name identifies an import. + // The name was unbound. + NoNameDefinition, + // The name identifies an immediate child. + ChildNameDefinition(Def, LastPrivate), + // The name identifies an import. + ImportNameDefinition(Def, LastPrivate), } impl<'a, 'v, 'tcx> Visitor<'v> for Resolver<'a, 'tcx> { @@ -277,7 +280,7 @@ enum FallbackSuggestion { TraitMethod(String), } -#[derive(Copy)] +#[derive(Copy, Clone)] enum TypeParameters<'a> { NoTypeParameters, HasTypeParameters( @@ -294,7 +297,7 @@ enum TypeParameters<'a> { // The rib kind controls the translation of local // definitions (`DefLocal`) to upvars (`DefUpvar`). -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum RibKind { // No translation needs to be applied. NormalRibKind, @@ -316,7 +319,7 @@ enum RibKind { ConstantItemRibKind } -#[derive(Copy)] +#[derive(Copy, Clone)] enum UseLexicalScopeFlag { DontUseLexicalScope, UseLexicalScope @@ -327,7 +330,7 @@ enum ModulePrefixResult { PrefixFound(Rc, usize) } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum NameSearchType { /// We're doing a name search in order to resolve a `use` directive. ImportSearch, @@ -337,7 +340,7 @@ enum NameSearchType { PathSearch, } -#[derive(Copy)] +#[derive(Copy, Clone)] enum BareIdentifierPatternResolution { FoundStructOrEnumVariant(Def, LastPrivate), FoundConst(Def, LastPrivate), @@ -369,7 +372,7 @@ enum ParentLink { } /// The type of module this is. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] enum ModuleKind { NormalModuleKind, TraitModuleKind, @@ -795,11 +798,6 @@ pub struct Resolver<'a, 'tcx:'a> { // The current self type if inside an impl (used for better errors). current_self_type: Option, - // The ident for the keyword "self". - self_name: Name, - // The ident for the non-keyword "Self". - type_self_name: Name, - // The idents for the primitive types. primitive_type_table: PrimitiveTypeTable, @@ -869,9 +867,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { current_trait_ref: None, current_self_type: None, - self_name: special_names::self_, - type_self_name: special_names::type_self, - primitive_type_table: PrimitiveTypeTable::new(), def_map: RefCell::new(NodeMap()), @@ -1822,7 +1817,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let mut self_type_rib = Rib::new(ItemRibKind); // plain insert (no renaming, types are not currently hygienic....) - let name = self.type_self_name; + let name = special_names::type_self; self_type_rib.bindings.insert(name, DlDef(DefSelfTy(item.id))); self.type_ribs.push(self_type_rib); @@ -2047,8 +2042,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn with_optional_trait_ref(&mut self, opt_trait_ref: Option<&TraitRef>, - f: F) -> T where - F: FnOnce(&mut Resolver) -> T, + f: F) + -> T + where F: FnOnce(&mut Resolver) -> T, { let mut new_val = None; if let Some(trait_ref) = opt_trait_ref { @@ -2585,11 +2581,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let span = path.span; let segments = &path.segments[..path.segments.len()-path_depth]; - let mk_res = |(def, lp)| PathResolution { - base_def: def, - last_private: lp, - depth: path_depth - }; + let mk_res = |(def, lp)| PathResolution::new(def, lp, path_depth); if path.global { let def = self.resolve_crate_relative_path(span, segments, namespace); @@ -2603,25 +2595,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { check_ribs, span); - if segments.len() > 1 { - let def = self.resolve_module_relative_path(span, segments, namespace); - match (def, unqualified_def) { - (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => { - self.session - .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, - id, span, - "unnecessary qualification".to_string()); - } - _ => () - } + if segments.len() <= 1 { + return unqualified_def.map(mk_res); + } - def.map(mk_res) - } else { - unqualified_def.map(mk_res) + let def = self.resolve_module_relative_path(span, segments, namespace); + match (def, unqualified_def) { + (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => { + self.session + .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, + id, span, + "unnecessary qualification".to_string()); + } + _ => {} } + + def.map(mk_res) } - // resolve a single identifier (used as a varref) + // Resolve a single identifier. fn resolve_identifier(&mut self, identifier: Ident, namespace: Namespace, @@ -2662,8 +2654,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match child_name_bindings.def_for_namespace(namespace) { Some(def) => { // Found it. Stop the search here. - let p = child_name_bindings.defined_in_public_namespace( - namespace); + let p = child_name_bindings.defined_in_public_namespace(namespace); let lp = if p {LastMod(AllPublic)} else { LastMod(DependsOn(def.def_id())) }; @@ -2734,8 +2725,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let containing_module; let last_private; - let module = self.current_module.clone(); - match self.resolve_module_path(module, + let current_module = self.current_module.clone(); + match self.resolve_module_path(current_module, &module_path[..], UseLexicalScope, span, @@ -2858,8 +2849,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match search_result { Some(DlDef(def)) => { - debug!("(resolving path in local ribs) resolved `{}` to \ - local: {:?}", + debug!("(resolving path in local ribs) resolved `{}` to local: {:?}", token::get_ident(ident), def); Some(def) @@ -2904,15 +2894,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { panic!("unexpected indeterminate result"); } Failed(err) => { - match err { - Some((span, msg)) => - self.resolve_error(span, &format!("failed to resolve. {}", - msg)), - None => () - } - debug!("(resolving item path by identifier in lexical scope) \ failed to resolve {}", token::get_name(name)); + + if let Some((span, msg)) = err { + self.resolve_error(span, &format!("failed to resolve. {}", msg)) + } + return None; } } @@ -2964,10 +2952,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } else { match this.resolve_module_path(root, - &name_path[..], - UseLexicalScope, - span, - PathSearch) { + &name_path[..], + UseLexicalScope, + span, + PathSearch) { Success((module, _)) => Some(module), _ => None } @@ -3203,8 +3191,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { false // Stop advancing }); - if method_scope && &token::get_name(self.self_name)[..] - == path_name { + if method_scope && + &token::get_name(special_names::self_)[..] == path_name { self.resolve_error( expr.span, "`self` is not available \ @@ -3539,7 +3527,7 @@ pub struct CrateMap { pub glob_map: Option } -#[derive(PartialEq,Copy)] +#[derive(PartialEq,Copy, Clone)] pub enum MakeGlobMap { Yes, No diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 44c803c77656d..f1a8507b17811 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -37,7 +37,7 @@ use std::rc::Rc; /// Contains data for specific types of import directives. -#[derive(Copy,Debug)] +#[derive(Copy, Clone,Debug)] pub enum ImportDirectiveSubclass { SingleImport(Name /* target */, Name /* source */), GlobImport diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index f7c0d6a983fb7..db724b0ef6b65 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -62,7 +62,7 @@ macro_rules! svec { }) } -#[derive(Copy, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum Row { Variable, Enum, diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index ea8197d0c407e..ef599a01e7c40 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -228,7 +228,7 @@ use syntax::codemap::Span; use syntax::fold::Folder; use syntax::ptr::P; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] struct ConstantExpr<'a>(&'a ast::Expr); impl<'a> ConstantExpr<'a> { @@ -311,7 +311,7 @@ impl<'a, 'tcx> Opt<'a, 'tcx> { } } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum BranchKind { NoBranch, Single, diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 51db1430ae250..05c366a645e76 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -2112,7 +2112,7 @@ pub fn llvm_linkage_by_name(name: &str) -> Option { /// Enum describing the origin of an LLVM `Value`, for linkage purposes. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum ValueOrigin { /// The LLVM `Value` is in this context because the corresponding item was /// assigned to the current compilation unit. diff --git a/src/librustc_trans/trans/basic_block.rs b/src/librustc_trans/trans/basic_block.rs index a0aca17538fa9..d3d055cda1202 100644 --- a/src/librustc_trans/trans/basic_block.rs +++ b/src/librustc_trans/trans/basic_block.rs @@ -13,7 +13,7 @@ use llvm::BasicBlockRef; use trans::value::{Users, Value}; use std::iter::{Filter, Map}; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct BasicBlock(pub BasicBlockRef); pub type Preds = Map bool>, fn(Value) -> BasicBlock>; diff --git a/src/librustc_trans/trans/callee.rs b/src/librustc_trans/trans/callee.rs index e33ec29017cc8..9eb46d3ff549a 100644 --- a/src/librustc_trans/trans/callee.rs +++ b/src/librustc_trans/trans/callee.rs @@ -60,7 +60,7 @@ use syntax::ast; use syntax::ast_map; use syntax::ptr::P; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct MethodData { pub llfn: ValueRef, pub llself: ValueRef, @@ -1110,7 +1110,7 @@ pub fn trans_args<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>, bcx } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum AutorefArg { DontAutorefArg, DoAutorefArg(ast::NodeId) diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs index 4897ae286d3e9..19891e9307229 100644 --- a/src/librustc_trans/trans/cleanup.rs +++ b/src/librustc_trans/trans/cleanup.rs @@ -153,7 +153,7 @@ pub struct CleanupScope<'blk, 'tcx: 'blk> { cached_landing_pad: Option, } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct CustomScopeIndex { index: usize } @@ -184,14 +184,14 @@ impl<'blk, 'tcx: 'blk> fmt::Debug for CleanupScopeKind<'blk, 'tcx> { } } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum EarlyExitLabel { UnwindExit, ReturnExit, LoopExit(ast::NodeId, usize) } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct CachedEarlyExit { label: EarlyExitLabel, cleanup_block: BasicBlockRef, @@ -209,7 +209,7 @@ pub trait Cleanup<'tcx> { pub type CleanupObj<'tcx> = Box+'tcx>; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum ScopeId { AstScope(ast::NodeId), CustomScope(CustomScopeIndex) @@ -982,7 +982,7 @@ impl EarlyExitLabel { /////////////////////////////////////////////////////////////////////////// // Cleanup types -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct DropValue<'tcx> { is_immediate: bool, must_unwind: bool, @@ -1021,12 +1021,12 @@ impl<'tcx> Cleanup<'tcx> for DropValue<'tcx> { } } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Heap { HeapExchange } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct FreeValue<'tcx> { ptr: ValueRef, heap: Heap, @@ -1061,7 +1061,7 @@ impl<'tcx> Cleanup<'tcx> for FreeValue<'tcx> { } } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct FreeSlice { ptr: ValueRef, size: ValueRef, @@ -1098,7 +1098,7 @@ impl<'tcx> Cleanup<'tcx> for FreeSlice { } } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct LifetimeEnd { ptr: ValueRef, } diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index 995f3caf58870..c5985e930e97b 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -343,7 +343,7 @@ pub fn gensym_name(name: &str) -> PathElem { * */ -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct NodeIdAndSpan { pub id: ast::NodeId, pub span: Span, @@ -1225,7 +1225,7 @@ pub fn drain_fulfillment_cx<'a,'tcx,T>(infcx: &infer::InferCtxt<'a,'tcx>, } // Key used to lookup values supplied for type parameters in an expr. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum ExprOrMethodCall { // Type parameters for a path like `None::` ExprId(ast::NodeId), diff --git a/src/librustc_trans/trans/controlflow.rs b/src/librustc_trans/trans/controlflow.rs index bd31580333fab..5b1ac88c2089b 100644 --- a/src/librustc_trans/trans/controlflow.rs +++ b/src/librustc_trans/trans/controlflow.rs @@ -40,6 +40,10 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>, let fcx = cx.fcx; debug!("trans_stmt({})", s.repr(cx.tcx())); + if cx.unreachable.get() { + return cx; + } + if cx.sess().asm_comments() { add_span_comment(cx, s.span, &s.repr(cx.tcx())); } @@ -76,6 +80,11 @@ pub fn trans_stmt<'blk, 'tcx>(cx: Block<'blk, 'tcx>, pub fn trans_stmt_semi<'blk, 'tcx>(cx: Block<'blk, 'tcx>, e: &ast::Expr) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_stmt_semi"); + + if cx.unreachable.get() { + return cx; + } + let ty = expr_ty(cx, e); if cx.fcx.type_needs_drop(ty) { expr::trans_to_lvalue(cx, e, "stmt").bcx @@ -89,6 +98,11 @@ pub fn trans_block<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, mut dest: expr::Dest) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_block"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; let mut bcx = bcx; @@ -141,6 +155,11 @@ pub fn trans_if<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, bcx.to_str(), if_id, bcx.expr_to_string(cond), thn.id, dest.to_string(bcx.ccx())); let _icx = push_ctxt("trans_if"); + + if bcx.unreachable.get() { + return bcx; + } + let mut bcx = bcx; let cond_val = unpack_result!(bcx, expr::trans(bcx, cond).to_llbool()); @@ -214,6 +233,11 @@ pub fn trans_while<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, body: &ast::Block) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_while"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; // bcx @@ -257,6 +281,11 @@ pub fn trans_loop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, body: &ast::Block) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_loop"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; // bcx @@ -296,12 +325,13 @@ pub fn trans_break_cont<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, exit: usize) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_break_cont"); - let fcx = bcx.fcx; if bcx.unreachable.get() { return bcx; } + let fcx = bcx.fcx; + // Locate loop that we will break to let loop_id = match opt_label { None => fcx.top_loop_scope(), @@ -341,6 +371,11 @@ pub fn trans_ret<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, retval_expr: Option<&ast::Expr>) -> Block<'blk, 'tcx> { let _icx = push_ctxt("trans_ret"); + + if bcx.unreachable.get() { + return bcx; + } + let fcx = bcx.fcx; let mut bcx = bcx; let dest = match (fcx.llretslotptr.get(), retval_expr) { @@ -372,6 +407,10 @@ pub fn trans_fail<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ccx = bcx.ccx(); let _icx = push_ctxt("trans_fail_value"); + if bcx.unreachable.get() { + return bcx; + } + let v_str = C_str_slice(ccx, fail_str); let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo); let filename = token::intern_and_get_ident(&loc.file.name); @@ -399,6 +438,10 @@ pub fn trans_fail_bounds_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ccx = bcx.ccx(); let _icx = push_ctxt("trans_fail_bounds_check"); + if bcx.unreachable.get() { + return bcx; + } + // Extract the file/line from the span let loc = bcx.sess().codemap().lookup_char_pos(call_info.span.lo); let filename = token::intern_and_get_ident(&loc.file.name); diff --git a/src/librustc_trans/trans/datum.rs b/src/librustc_trans/trans/datum.rs index 7b983ca4ac6ac..a736a9fe88a14 100644 --- a/src/librustc_trans/trans/datum.rs +++ b/src/librustc_trans/trans/datum.rs @@ -172,7 +172,7 @@ impl Drop for Rvalue { fn drop(&mut self) { } } -#[derive(Copy, PartialEq, Eq, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum RvalueMode { /// `val` is a pointer to the actual value (and thus has type *T) ByRef, diff --git a/src/librustc_trans/trans/debuginfo.rs b/src/librustc_trans/trans/debuginfo.rs index 8e9ae2eba0bcd..2747288b60755 100644 --- a/src/librustc_trans/trans/debuginfo.rs +++ b/src/librustc_trans/trans/debuginfo.rs @@ -2382,7 +2382,7 @@ impl<'tcx> VariantMemberDescriptionFactory<'tcx> { } } -#[derive(Copy)] +#[derive(Copy, Clone)] enum EnumDiscriminantInfo { RegularDiscriminant(DIType), OptimizedDiscriminant, @@ -3106,7 +3106,7 @@ impl MetadataCreationResult { } } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum InternalDebugLocation { KnownLocation { scope: DIScope, line: usize, col: usize }, UnknownLocation diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 46cbd1936002a..5a79aa35bfae1 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -94,7 +94,7 @@ use std::rc::Rc; // These are passed around by the code generating functions to track the // destination of a computation's value. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum Dest { SaveIn(ValueRef), Ignore, @@ -2038,7 +2038,7 @@ fn float_cast(bcx: Block, } else { llsrc }; } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum cast_kind { cast_pointer, cast_integral, diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index f7433e6a77409..c7857d6a775f3 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -57,7 +57,7 @@ mod basic_block; mod llrepr; mod cleanup; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct ModuleTranslation { pub llcx: ContextRef, pub llmod: ModuleRef, diff --git a/src/librustc_trans/trans/tvec.rs b/src/librustc_trans/trans/tvec.rs index 34dfb0eebcf9d..791b58d88a93e 100644 --- a/src/librustc_trans/trans/tvec.rs +++ b/src/librustc_trans/trans/tvec.rs @@ -33,7 +33,7 @@ use util::ppaux::ty_to_string; use syntax::ast; use syntax::parse::token::InternedString; -#[derive(Copy)] +#[derive(Copy, Clone)] struct VecTypes<'tcx> { unit_ty: Ty<'tcx>, llunit_ty: Type diff --git a/src/librustc_trans/trans/value.rs b/src/librustc_trans/trans/value.rs index c2d91e4e16024..bc71278c15743 100644 --- a/src/librustc_trans/trans/value.rs +++ b/src/librustc_trans/trans/value.rs @@ -14,7 +14,7 @@ use trans::basic_block::BasicBlock; use trans::common::Block; use libc::c_uint; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Value(pub ValueRef); macro_rules! opt_val { ($e:expr) => ( @@ -125,7 +125,7 @@ impl Value { } /// Wrapper for LLVM UseRef -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Use(UseRef); impl Use { diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 0d6ca7430d38e..939142cff1c32 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -140,13 +140,7 @@ pub trait AstConv<'tcx> { span: Span, _trait_ref: Rc>, _item_name: ast::Name) - -> Ty<'tcx> - { - span_err!(self.tcx().sess, span, E0213, - "associated types are not accepted in this context"); - - self.tcx().types.err - } + -> Ty<'tcx>; } pub fn ast_region_to_region(tcx: &ty::ctxt, lifetime: &ast::Lifetime) @@ -924,9 +918,12 @@ fn ast_path_to_ty<'tcx>( } }; - let substs = ast_path_substs_for_ty(this, rscope, - span, param_mode, - &generics, item_segment); + let substs = ast_path_substs_for_ty(this, + rscope, + span, + param_mode, + &generics, + item_segment); // FIXME(#12938): This is a hack until we have full support for DST. if Some(did) == this.tcx().lang_items.owned_box() { @@ -1044,6 +1041,12 @@ fn report_ambiguous_associated_type(tcx: &ty::ctxt, type_str, trait_str, name); } +// Create a type from a a path to an associated type. +// For a path A::B::C::D, ty and ty_path_def are the type and def for A::B::C +// and item_segment is the path segment for D. We return a type and a def for +// the whole path. +// Will fail except for T::A and Self::A; i.e., if ty/ty_path_def are not a type +// parameter or Self. fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, span: Span, ty: Ty<'tcx>, @@ -1052,35 +1055,43 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, -> (Ty<'tcx>, def::Def) { let tcx = this.tcx(); - check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); let assoc_name = item_segment.identifier.name; - let is_param = match (&ty.sty, ty_path_def) { - (&ty::ty_param(_), def::DefTyParam(..)) | - (&ty::ty_param(_), def::DefSelfTy(_)) => true, - _ => false - }; + debug!("associated_path_def_to_ty: {}::{}", ty.repr(tcx), token::get_name(assoc_name)); - let ty_param_node_id = if is_param { - ty_path_def.local_node_id() - } else { - report_ambiguous_associated_type( - tcx, span, &ty.user_string(tcx), "Trait", &token::get_name(assoc_name)); - return (tcx.types.err, ty_path_def); - }; + check_path_args(tcx, slice::ref_slice(item_segment), NO_TPS | NO_REGIONS); + + // Check that the path prefix given by ty/ty_path_def is a type parameter/Self. + match (&ty.sty, ty_path_def) { + (&ty::ty_param(_), def::DefTyParam(..)) | + (&ty::ty_param(_), def::DefSelfTy(_)) => {} + _ => { + report_ambiguous_associated_type(tcx, + span, + &ty.user_string(tcx), + "Trait", + &token::get_name(assoc_name)); + return (tcx.types.err, ty_path_def); + } + } + let ty_param_node_id = ty_path_def.local_node_id(); let ty_param_name = tcx.ty_param_defs.borrow().get(&ty_param_node_id).unwrap().name; let bounds = match this.get_type_parameter_bounds(span, ty_param_node_id) { Ok(v) => v, - Err(ErrorReported) => { return (tcx.types.err, ty_path_def); } + Err(ErrorReported) => { + return (tcx.types.err, ty_path_def); + } }; - // ensure the super predicates and stop if we encountered an error + // Ensure the super predicates and stop if we encountered an error. if bounds.iter().any(|b| this.ensure_super_predicates(span, b.def_id()).is_err()) { return (this.tcx().types.err, ty_path_def); } + // Check that there is exactly one way to find an associated type with the + // correct name. let mut suitable_bounds: Vec<_> = traits::transitive_bounds(tcx, &bounds) .filter(|b| this.trait_defines_associated_type_named(b.def_id(), assoc_name)) @@ -1118,7 +1129,8 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, // by type collection, which may be in progress at this point. match this.tcx().map.expect_item(trait_did.node).node { ast::ItemTrait(_, _, _, ref trait_items) => { - let item = trait_items.iter().find(|i| i.ident.name == assoc_name) + let item = trait_items.iter() + .find(|i| i.ident.name == assoc_name) .expect("missing associated type"); ast_util::local_def(item.id) } @@ -1129,6 +1141,7 @@ fn associated_path_def_to_ty<'tcx>(this: &AstConv<'tcx>, 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)) } @@ -1150,8 +1163,11 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>, ty } else { let path_str = ty::item_path_str(tcx, trait_def_id); - report_ambiguous_associated_type( - tcx, span, "Type", &path_str, &token::get_ident(item_segment.identifier)); + report_ambiguous_associated_type(tcx, + span, + "Type", + &path_str, + &token::get_ident(item_segment.identifier)); return tcx.types.err; }; @@ -1204,13 +1220,15 @@ pub fn ast_ty_arg_to_ty<'tcx>(this: &AstConv<'tcx>, } } +// Note that both base_segments and assoc_segments may be empty, although not at +// the same time. pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, rscope: &RegionScope, span: Span, param_mode: PathParamMode, - def: &mut def::Def, + def: &def::Def, opt_self_ty: Option>, - segments: &[ast::PathSegment], + base_segments: &[ast::PathSegment], assoc_segments: &[ast::PathSegment]) -> Ty<'tcx> { let tcx = this.tcx(); @@ -1226,52 +1244,64 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, span, param_mode, trait_def_id, - segments.last().unwrap(), + base_segments.last().unwrap(), &mut projection_bounds); - check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS); - trait_ref_to_object_type(this, rscope, span, trait_ref, - projection_bounds, &[]) + check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); + trait_ref_to_object_type(this, + rscope, + span, + trait_ref, + projection_bounds, + &[]) } def::DefTy(did, _) | def::DefStruct(did) => { - check_path_args(tcx, segments.init(), NO_TPS | NO_REGIONS); + check_path_args(tcx, base_segments.init(), NO_TPS | NO_REGIONS); ast_path_to_ty(this, rscope, span, param_mode, did, - segments.last().unwrap()) + base_segments.last().unwrap()) } def::DefTyParam(space, index, _, name) => { - check_path_args(tcx, segments, NO_TPS | NO_REGIONS); + check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_param(tcx, space, index, name) } def::DefSelfTy(_) => { - // n.b.: resolve guarantees that the this type only appears in a + // N.b.: resolve guarantees that the this type only appears in a // trait, which we rely upon in various places when creating - // substs - check_path_args(tcx, segments, NO_TPS | NO_REGIONS); + // substs. + check_path_args(tcx, base_segments, NO_TPS | NO_REGIONS); ty::mk_self_type(tcx) } def::DefAssociatedTy(trait_did, _) => { - check_path_args(tcx, &segments[..segments.len()-2], NO_TPS | NO_REGIONS); - qpath_to_ty(this, rscope, span, param_mode, - opt_self_ty, trait_did, - &segments[segments.len()-2], - segments.last().unwrap()) + check_path_args(tcx, &base_segments[..base_segments.len()-2], NO_TPS | NO_REGIONS); + qpath_to_ty(this, + rscope, + span, + param_mode, + opt_self_ty, + trait_did, + &base_segments[base_segments.len()-2], + base_segments.last().unwrap()) } def::DefMod(id) => { // Used as sentinel by callers to indicate the `::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 ::a::b::c") - } else { - span_err!(tcx.sess, span, E0247, "found module name used as a type: {}", + + if !base_segments.is_empty() { + span_err!(tcx.sess, + span, + E0247, + "found module name used as a type: {}", tcx.map.node_to_string(id.node)); return this.tcx().types.err; } + + opt_self_ty.expect("missing T in ::a::b::c") } def::DefPrimTy(prim_ty) => { - prim_ty_to_ty(tcx, segments, prim_ty) + prim_ty_to_ty(tcx, base_segments, prim_ty) } _ => { span_err!(tcx.sess, span, E0248, @@ -1282,15 +1312,19 @@ pub fn finish_resolving_def_to_ty<'tcx>(this: &AstConv<'tcx>, // If any associated type segments remain, attempt to resolve them. let mut ty = base_ty; + let mut def = *def; for segment in assoc_segments { if ty.sty == ty::ty_err { break; } // This is pretty bad (it will fail except for T::A and Self::A). - let (a_ty, a_def) = associated_path_def_to_ty(this, span, - ty, *def, segment); + let (a_ty, a_def) = associated_path_def_to_ty(this, + span, + ty, + def, + segment); ty = a_ty; - *def = a_def; + def = a_def; } ty } @@ -1378,13 +1412,16 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, tcx.sess.span_bug(ast_ty.span, &format!("unbound path {}", ast_ty.repr(tcx))) }; - let mut def = path_res.base_def; + let def = path_res.base_def; let base_ty_end = path.segments.len() - path_res.depth; let opt_self_ty = maybe_qself.as_ref().map(|qself| { ast_ty_to_ty(this, rscope, &qself.ty) }); - let ty = finish_resolving_def_to_ty(this, rscope, ast_ty.span, - PathParamMode::Explicit, &mut def, + let ty = finish_resolving_def_to_ty(this, + rscope, + ast_ty.span, + PathParamMode::Explicit, + &def, opt_self_ty, &path.segments[..base_ty_end], &path.segments[base_ty_end..]); diff --git a/src/librustc_typeck/check/callee.rs b/src/librustc_typeck/check/callee.rs index 31ac0a57ba0e1..3f9c14e0afe39 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/src/librustc_typeck/check/callee.rs @@ -83,9 +83,7 @@ pub fn check_call<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, UnresolvedTypeAction::Error, LvaluePreference::NoPreference, |adj_ty, idx| { - let autoderefref = ty::AutoDerefRef { autoderefs: idx, autoref: None }; - try_overloaded_call_step(fcx, call_expr, callee_expr, - adj_ty, autoderefref) + try_overloaded_call_step(fcx, call_expr, callee_expr, adj_ty, idx) }); match result { @@ -119,13 +117,15 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, call_expr: &'tcx ast::Expr, callee_expr: &'tcx ast::Expr, adjusted_ty: Ty<'tcx>, - autoderefref: ty::AutoDerefRef<'tcx>) + autoderefs: usize) -> Option> { - debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefref={})", + debug!("try_overloaded_call_step(call_expr={}, adjusted_ty={}, autoderefs={})", call_expr.repr(fcx.tcx()), adjusted_ty.repr(fcx.tcx()), - autoderefref.repr(fcx.tcx())); + autoderefs); + + let autoderefref = ty::AutoDerefRef { autoderefs: autoderefs, autoref: None }; // If the callee is a bare function or a closure, then we're all set. match structurally_resolved_type(fcx, callee_expr.span, adjusted_ty).sty { @@ -161,6 +161,18 @@ fn try_overloaded_call_step<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, } } + // Hack: we know that there are traits implementing Fn for &F + // where F:Fn and so forth. In the particular case of types + // like `x: &mut FnMut()`, if there is a call `x()`, we would + // normally translate to `FnMut::call_mut(&mut x, ())`, but + // that winds up requiring `mut x: &mut FnMut()`. A little + // over the top. The simplest fix by far is to just ignore + // this case and deref again, so we wind up with + // `FnMut::call_mut(&mut *x, ())`. + ty::ty_rptr(..) if autoderefs == 0 => { + return None; + } + _ => {} } diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs index ae1dbbb1b00ad..ced6cec3ef0dc 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/src/librustc_typeck/check/coercion.rs @@ -62,12 +62,11 @@ use check::{autoderef, FnCtxt, NoPreference, PreferMutLvalue, UnresolvedTypeAction}; -use middle::infer::{self, cres, Coercion, TypeTrace}; -use middle::infer::combine::Combine; -use middle::infer::sub::Sub; +use middle::infer::{self, Coercion}; use middle::subst; use middle::ty::{AutoPtr, AutoDerefRef, AdjustDerefRef, AutoUnsize, AutoUnsafe}; use middle::ty::{self, mt, Ty}; +use middle::ty_relate::RelateResult; use util::common::indent; use util::ppaux; use util::ppaux::Repr; @@ -76,10 +75,10 @@ use syntax::ast; struct Coerce<'a, 'tcx: 'a> { fcx: &'a FnCtxt<'a, 'tcx>, - trace: TypeTrace<'tcx> + origin: infer::TypeOrigin, } -type CoerceResult<'tcx> = cres<'tcx, Option>>; +type CoerceResult<'tcx> = RelateResult<'tcx, Option>>; impl<'f, 'tcx> Coerce<'f, 'tcx> { fn tcx(&self) -> &ty::ctxt<'tcx> { @@ -87,14 +86,16 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } fn subtype(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> { - let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); - try!(sub.tys(a, b)); + try!(self.fcx.infcx().sub_types(false, self.origin.clone(), a, b)); Ok(None) // No coercion required. } - fn outlives(&self, a: ty::Region, b: ty::Region) -> cres<'tcx, ()> { - let sub = Sub(self.fcx.infcx().combine_fields(false, self.trace.clone())); - try!(sub.regions(b, a)); + fn outlives(&self, + origin: infer::SubregionOrigin<'tcx>, + a: ty::Region, + b: ty::Region) + -> RelateResult<'tcx, ()> { + infer::mk_subr(self.fcx.infcx(), origin, b, a); Ok(()) } @@ -190,7 +191,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { _ => return self.subtype(a, b) } - let coercion = Coercion(self.trace.clone()); + let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let autoref = Some(AutoPtr(r_borrow, mutbl_b, None)); @@ -214,7 +215,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } let ty = ty::mk_rptr(self.tcx(), r_borrow, mt {ty: inner_ty, mutbl: mutbl_b}); - if let Err(err) = self.fcx.infcx().try(|_| self.subtype(ty, b)) { + if let Err(err) = self.subtype(ty, b) { if first_error.is_none() { first_error = Some(err); } @@ -264,12 +265,12 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { return Err(ty::terr_mutability); } - let coercion = Coercion(self.trace.clone()); + let coercion = Coercion(self.origin.span()); let r_borrow = self.fcx.infcx().next_region_var(coercion); let ty = ty::mk_rptr(self.tcx(), self.tcx().mk_region(r_borrow), ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + try!(self.subtype(ty, b)); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({:?})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -290,7 +291,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty = ty::mk_ptr(self.tcx(), ty::mt{ty: ty, mutbl: mt_b.mutbl}); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + try!(self.subtype(ty, b)); debug!("Success, coerced with AutoDerefRef(1, \ AutoPtr(AutoUnsize({:?})))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -306,7 +307,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { match self.unsize_ty(t_a, t_b) { Some((ty, kind)) => { let ty = ty::mk_uniq(self.tcx(), ty); - try!(self.fcx.infcx().try(|_| self.subtype(ty, b))); + try!(self.subtype(ty, b)); debug!("Success, coerced with AutoDerefRef(1, \ AutoUnsizeUniq({:?}))", kind); Ok(Some(AdjustDerefRef(AutoDerefRef { @@ -365,9 +366,10 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1); // relate `a1` to `b` - let result = self.fcx.infcx().try(|_| { + let result = self.fcx.infcx().commit_if_ok(|_| { // it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b - try!(self.outlives(data_a.bounds.region_bound, + try!(self.outlives(infer::RelateObjectBound(self.origin.span()), + data_a.bounds.region_bound, data_b.bounds.region_bound)); self.subtype(ty_a1, ty_b) }); @@ -399,7 +401,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut result = None; let tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate(); for (i, (tp_a, tp_b)) in tps { - if self.fcx.infcx().try(|_| self.subtype(*tp_a, *tp_b)).is_ok() { + if self.subtype(*tp_a, *tp_b).is_ok() { continue; } match self.unsize_ty(*tp_a, *tp_b) { @@ -408,7 +410,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let mut new_substs = substs_a.clone(); new_substs.types.get_mut_slice(subst::TypeSpace)[i] = new_tp; let ty = ty::mk_struct(tcx, did_a, tcx.mk_substs(new_substs)); - if self.fcx.infcx().try(|_| self.subtype(ty, ty_b)).is_err() { + if self.subtype(ty, ty_b).is_err() { debug!("Unsized type parameter '{}', but still \ could not match types {} and {}", ppaux::ty_to_string(tcx, *tp_a), @@ -534,14 +536,13 @@ pub fn mk_assignty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, expr: &ast::Expr, a: Ty<'tcx>, b: Ty<'tcx>) - -> cres<'tcx, ()> { + -> RelateResult<'tcx, ()> { debug!("mk_assignty({} -> {})", a.repr(fcx.tcx()), b.repr(fcx.tcx())); let adjustment = try!(indent(|| { - fcx.infcx().commit_if_ok(|| { - let origin = infer::ExprAssignable(expr.span); + fcx.infcx().commit_if_ok(|_| { Coerce { fcx: fcx, - trace: infer::TypeTrace::types(origin, false, a, b) + origin: infer::ExprAssignable(expr.span), }.coerce(expr, a, b) }) })); diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs index 1c5f2c5607857..532277d75b2e0 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/src/librustc_typeck/check/compare_method.rs @@ -282,7 +282,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>, let trait_fty = ty::mk_bare_fn(tcx, None, tcx.mk_bare_fn(trait_m.fty.clone())); let trait_fty = trait_fty.subst(tcx, &trait_to_skol_substs); - let err = infcx.try(|snapshot| { + let err = infcx.commit_if_ok(|snapshot| { let origin = infer::MethodCompatCheck(impl_m_span); let (impl_sig, _) = diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 49f4399b2c7b4..2f7e0073e1751 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -95,7 +95,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( ty::lookup_item_type(tcx, self_type_did); let infcx = infer::new_infer_ctxt(tcx); - infcx.try(|snapshot| { + infcx.commit_if_ok(|snapshot| { let (named_type_to_skolem, skol_map) = infcx.construct_skolemized_subst(named_type_generics, snapshot); let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem); diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs index af33cdb393263..677ab56852434 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/src/librustc_typeck/check/method/mod.rs @@ -52,7 +52,7 @@ pub enum MethodError { // A pared down enum describing just the places from which a method // candidate can arise. Used for error reporting only. -#[derive(Copy, PartialOrd, Ord, PartialEq, Eq)] +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] pub enum CandidateSource { ImplSource(ast::DefId), TraitSource(/* trait id */ ast::DefId), diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs index 6349ea57f2ff1..41eae88158905 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/src/librustc_typeck/check/method/probe.rs @@ -109,7 +109,7 @@ pub enum PickAdjustment { AutoRef(ast::Mutability, Box), } -#[derive(PartialEq, Eq, Copy)] +#[derive(PartialEq, Eq, Copy, Clone)] pub enum Mode { // An expression of the form `receiver.method_name(...)`. // Autoderefs are performed on `receiver`, lookup is done based on the @@ -1130,7 +1130,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> { /////////////////////////////////////////////////////////////////////////// // MISCELLANY - fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::ures<'tcx> { + fn make_sub_ty(&self, sub: Ty<'tcx>, sup: Ty<'tcx>) -> infer::UnitResult<'tcx> { self.infcx().sub_types(false, infer::Misc(DUMMY_SP), sub, sup) } diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index 9832fe1cb6eac..c5ff8a14bc1cf 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -266,7 +266,7 @@ fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, }).2.is_some() } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct TraitInfo { pub def_id: ast::DefId, } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index d6b14e84d919f..156fbfede9c98 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -205,7 +205,7 @@ struct CastCheck<'tcx> { /// When type-checking an expression, we propagate downward /// whatever type hint we are able in the form of an `Expectation`. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Expectation<'tcx> { /// We know nothing about what type this expression should have. NoExpectation, @@ -1952,14 +1952,14 @@ impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> { } } -#[derive(Copy, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum LvaluePreference { PreferMutLvalue, NoPreference } /// Whether `autoderef` requires types to resolve. -#[derive(Copy, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum UnresolvedTypeAction { /// Produce an error and return `ty_err` whenever a type cannot /// be resolved (i.e. it is `ty_infer`). @@ -3339,7 +3339,7 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, &format!("unbound path {}", expr.repr(tcx))) }; - let mut def = path_res.base_def; + let def = path_res.base_def; if path_res.depth == 0 { let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, def); @@ -3349,9 +3349,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, } else { let ty_segments = path.segments.init(); let base_ty_end = path.segments.len() - path_res.depth; - let ty = astconv::finish_resolving_def_to_ty(fcx, fcx, expr.span, + let ty = astconv::finish_resolving_def_to_ty(fcx, + fcx, + expr.span, PathParamMode::Optional, - &mut def, + &def, opt_self_ty, &ty_segments[..base_ty_end], &ty_segments[base_ty_end..]); diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 3edea6d300444..9171367468026 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -1542,7 +1542,7 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>, debug!("projection_bounds: outlives={} (2)", outlives.repr(tcx)); - let region_result = infcx.try(|_| { + let region_result = infcx.commit_if_ok(|_| { let (outlives, _) = infcx.replace_late_bound_regions_with_fresh_var( span, diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs index 23e31df539526..a86e2b17c93b8 100644 --- a/src/librustc_typeck/check/wf.rs +++ b/src/librustc_typeck/check/wf.rs @@ -249,11 +249,6 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { &fcx.inh.param_env.free_substs, &trait_ref); - if fcx.tcx().lang_items.copy_trait() == Some(trait_ref.def_id) { - // This is checked in coherence. - return - } - // We are stricter on the trait-ref in an impl than the // self-type. In particular, we enforce region // relationships. The reason for this is that (at least diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 4d7a046fc607b..37f43252483aa 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -350,7 +350,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { /////////////////////////////////////////////////////////////////////////// // Resolution reason. -#[derive(Copy)] +#[derive(Copy, Clone)] enum ResolveReason { ResolvingExpr(Span), ResolvingLocal(Span), diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs index eaf07a3ef13a7..51d0c18872dc4 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/src/librustc_typeck/coherence/mod.rs @@ -30,7 +30,6 @@ use middle::ty::{ty_uint, ty_closure, ty_uniq, ty_bare_fn}; use middle::ty::ty_projection; use middle::ty; use CrateCtxt; -use middle::infer::combine::Combine; use middle::infer::InferCtxt; use middle::infer::new_infer_ctxt; use std::collections::HashSet; diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index dd306c4da862d..8f1b8bf109215 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -135,7 +135,7 @@ struct ItemCtxt<'a,'tcx:'a> { param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a), } -#[derive(Copy, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] enum AstConvRequest { GetItemTypeScheme(ast::DefId), GetTraitDef(ast::DefId), diff --git a/src/librustc_typeck/rscope.rs b/src/librustc_typeck/rscope.rs index f1050a936e276..c908e21626e56 100644 --- a/src/librustc_typeck/rscope.rs +++ b/src/librustc_typeck/rscope.rs @@ -40,7 +40,7 @@ pub trait RegionScope { // A scope in which all regions must be explicitly named. This is used // for types that appear in structs and so on. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct ExplicitRscope; impl RegionScope for ExplicitRscope { diff --git a/src/librustc_typeck/variance.rs b/src/librustc_typeck/variance.rs index b014238b6f286..b83d8fc6af7fa 100644 --- a/src/librustc_typeck/variance.rs +++ b/src/librustc_typeck/variance.rs @@ -295,10 +295,10 @@ pub fn infer_variance(tcx: &ty::ctxt) { type VarianceTermPtr<'a> = &'a VarianceTerm<'a>; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] struct InferredIndex(usize); -#[derive(Copy)] +#[derive(Copy, Clone)] enum VarianceTerm<'a> { ConstantTerm(ty::Variance), TransformTerm(VarianceTermPtr<'a>, VarianceTermPtr<'a>), @@ -336,7 +336,7 @@ struct TermsContext<'a, 'tcx: 'a> { inferred_infos: Vec> , } -#[derive(Copy, Debug, PartialEq)] +#[derive(Copy, Clone, Debug, PartialEq)] enum ParamKind { TypeParam, RegionParam, @@ -560,7 +560,7 @@ struct ConstraintContext<'a, 'tcx: 'a> { /// Declares that the variable `decl_id` appears in a location with /// variance `variance`. -#[derive(Copy)] +#[derive(Copy, Clone)] struct Constraint<'a> { inferred: InferredIndex, variance: &'a VarianceTerm<'a>, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index e4d9fac5b9cb5..e0ed83f401945 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2392,7 +2392,7 @@ fn resolve_type(cx: &DocContext, }; match def { - def::DefSelfTy(..) => { + def::DefSelfTy(..) if path.segments.len() == 1 => { return Generic(token::get_name(special_idents::type_self.name).to_string()); } def::DefPrimTy(p) => match p { @@ -2412,7 +2412,9 @@ fn resolve_type(cx: &DocContext, ast::TyFloat(ast::TyF32) => return Primitive(F32), ast::TyFloat(ast::TyF64) => return Primitive(F64), }, - def::DefTyParam(_, _, _, n) => return Generic(token::get_name(n).to_string()), + def::DefTyParam(_, _, _, n) => { + return Generic(token::get_name(n).to_string()) + } _ => {} }; let did = register_def(&*cx, def); diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index df6beab0f5832..ed37b973f787e 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -30,19 +30,19 @@ use html::render::{cache, CURRENT_LOCATION_KEY}; /// Helper to render an optional visibility with a space after it (if the /// visibility is preset) -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct VisSpace(pub Option); /// Similarly to VisSpace, this structure is used to render a function style with a /// space after it. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct UnsafetySpace(pub ast::Unsafety); /// Wrapper struct for properly emitting a method declaration. pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl); /// Similar to VisSpace, but used for mutability -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct MutableSpace(pub clean::Mutability); /// Similar to VisSpace, but used for mutability -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct RawMutableSpace(pub clean::Mutability); /// Wrapper struct for properly emitting the stability level. pub struct Stability<'a>(pub &'a Option); diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 179418174d950..ac097d051b286 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -225,7 +225,7 @@ struct Source<'a>(&'a str); // Helper structs for rendering items/sidebars and carrying along contextual // information -#[derive(Copy)] +#[derive(Copy, Clone)] struct Item<'a> { cx: &'a Context, item: &'a clean::Item, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 1ff3411f8fc14..d1dcfc2600868 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -333,7 +333,7 @@ fn acquire_input(input: &str, fn parse_externs(matches: &getopts::Matches) -> Result { let mut externs = HashMap::new(); for arg in &matches.opt_strs("extern") { - let mut parts = arg.splitn(1, '='); + let mut parts = arg.splitn(2, '='); let name = match parts.next() { Some(s) => s, None => { diff --git a/src/librustdoc/stability_summary.rs b/src/librustdoc/stability_summary.rs index f75fced3bc26d..3e4f6896ee68d 100644 --- a/src/librustdoc/stability_summary.rs +++ b/src/librustdoc/stability_summary.rs @@ -27,7 +27,7 @@ use html::render::cache; #[derive(RustcEncodable, RustcDecodable, PartialEq, Eq)] /// The counts for each stability level. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Counts { pub deprecated: u64, pub unstable: u64, diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index babbe15b17df5..f5bee6240d46c 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -19,7 +19,6 @@ use std::path::PathBuf; use std::process::Command; use std::str; use std::sync::{Arc, Mutex}; -use std::thunk::Thunk; use testing; use rustc_lint; @@ -366,7 +365,7 @@ impl Collector { ignore: should_ignore, should_panic: testing::ShouldPanic::No, // compiler failures are test failures }, - testfn: testing::DynTestFn(Thunk::new(move|| { + testfn: testing::DynTestFn(Box::new(move|| { runtest(&test, &cratename, libs, diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index dc44536d60cea..0676edf81696f 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -62,7 +62,7 @@ pub trait FromHex { } /// Errors that can occur when decoding a hex encoded string -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum FromHexError { /// The input contained a character not part of the hex format InvalidHexCharacter(char, usize), diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index cdfe212bf23dd..5890bdec8c1bc 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -278,7 +278,7 @@ pub enum DecoderError { ApplicationError(string::String) } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum EncoderError { FmtError(fmt::Error), BadHashmapKey, diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 053ceceb49621..dec6d1e2209ad 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -87,6 +87,9 @@ struct RawBucket { } impl Copy for RawBucket {} +impl Clone for RawBucket { + fn clone(&self) -> RawBucket { *self } +} pub struct Bucket { raw: RawBucket, @@ -95,6 +98,9 @@ pub struct Bucket { } impl Copy for Bucket {} +impl Clone for Bucket { + fn clone(&self) -> Bucket { *self } +} pub struct EmptyBucket { raw: RawBucket, @@ -129,7 +135,7 @@ struct GapThenFull { /// A hash that is not zero, since we use a hash of zero to represent empty /// buckets. -#[derive(PartialEq, Copy)] +#[derive(PartialEq, Copy, Clone)] pub struct SafeHash { hash: u64, } diff --git a/src/libstd/error.rs b/src/libstd/error.rs new file mode 100644 index 0000000000000..150ffcdd77a9f --- /dev/null +++ b/src/libstd/error.rs @@ -0,0 +1,152 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Traits for working with Errors. +//! +//! # The `Error` trait +//! +//! `Error` is a trait representing the basic expectations for error values, +//! i.e. values of type `E` in `Result`. At a minimum, errors must provide +//! a description, but they may optionally provide additional detail (via +//! `Display`) and cause chain information: +//! +//! ``` +//! use std::fmt::Display; +//! +//! trait Error: Display { +//! fn description(&self) -> &str; +//! +//! fn cause(&self) -> Option<&Error> { None } +//! } +//! ``` +//! +//! The `cause` method is generally used when errors cross "abstraction +//! boundaries", i.e. when a one module must report an error that is "caused" +//! by an error from a lower-level module. This setup makes it possible for the +//! high-level module to provide its own errors that do not commit to any +//! particular implementation, but also reveal some of its implementation for +//! debugging via `cause` chains. + +#![stable(feature = "rust1", since = "1.0.0")] + +// A note about crates and the facade: +// +// Originally, the `Error` trait was defined in libcore, and the impls +// were scattered about. However, coherence objected to this +// arrangement, because to create the blanket impls for `Box` required +// knowing that `&str: !Error`, and we have no means to deal with that +// sort of conflict just now. Therefore, for the time being, we have +// moved the `Error` trait into libstd. As we evolve a sol'n to the +// coherence challenge (e.g., specialization, neg impls, etc) we can +// reconsider what crate these items belong in. + +use boxed::Box; +use convert::From; +use fmt::{self, Debug, Display}; +use marker::Send; +use num; +use option::Option; +use option::Option::None; +use str; +use string::{self, String}; + +/// Base functionality for all errors in Rust. +#[stable(feature = "rust1", since = "1.0.0")] +pub trait Error: Debug + Display { + /// A short description of the error. + /// + /// The description should not contain newlines or sentence-ending + /// punctuation, to facilitate embedding in larger user-facing + /// strings. + #[stable(feature = "rust1", since = "1.0.0")] + fn description(&self) -> &str; + + /// The lower-level cause of this error, if any. + #[stable(feature = "rust1", since = "1.0.0")] + fn cause(&self) -> Option<&Error> { None } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + 'a> From for Box { + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, 'b> From<&'b str> for Box { + fn from(err: &'b str) -> Box { + #[derive(Debug)] + struct StringError(String); + + impl Error for StringError { + fn description(&self) -> &str { &self.0 } + } + + impl Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } + } + + Box::new(StringError(String::from_str(err))) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for str::ParseBoolError { + fn description(&self) -> &str { "failed to parse bool" } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for str::Utf8Error { + fn description(&self) -> &str { + match *self { + str::Utf8Error::TooShort => "invalid utf-8: not enough bytes", + str::Utf8Error::InvalidByte(..) => "invalid utf-8: corrupt contents", + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for num::ParseIntError { + fn description(&self) -> &str { + self.description() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for num::ParseFloatError { + fn description(&self) -> &str { + self.description() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for string::FromUtf8Error { + fn description(&self) -> &str { + "invalid utf-8" + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for string::FromUtf16Error { + fn description(&self) -> &str { + "invalid utf-16" + } +} + diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index a014d6e68ffb1..c6335015d7251 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -101,18 +101,14 @@ fn append_to_string(buf: &mut String, f: F) -> Result fn read_to_end(r: &mut R, buf: &mut Vec) -> Result { let start_len = buf.len(); let mut len = start_len; - let mut cap_bump = 16; + let mut new_write_size = 16; let ret; loop { if len == buf.len() { - if buf.capacity() == buf.len() { - if cap_bump < DEFAULT_BUF_SIZE { - cap_bump *= 2; - } - buf.reserve(cap_bump); + if new_write_size < DEFAULT_BUF_SIZE { + new_write_size *= 2; } - let new_area = buf.capacity() - buf.len(); - buf.extend(iter::repeat(0).take(new_area)); + buf.extend(iter::repeat(0).take(new_write_size)); } match r.read(&mut buf[len..]) { diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 41ac3d60df558..5c9ff544fa3e8 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -183,7 +183,7 @@ pub use core::raw; pub use core::simd; pub use core::result; pub use core::option; -pub use core::error; +pub mod error; #[cfg(not(test))] pub use alloc::boxed; pub use alloc::rc; @@ -243,6 +243,7 @@ mod uint_macros; #[path = "num/f64.rs"] pub mod f64; pub mod ascii; + pub mod thunk; /* Common traits */ diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index c45230e91ba9e..886f252fb1926 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -441,7 +441,7 @@ impl ToSocketAddrs for str { } // split the string by ':' and convert the second part to u16 - let mut parts_iter = self.rsplitn(1, ':'); + let mut parts_iter = self.rsplitn(2, ':'); let port_str = try_opt!(parts_iter.next(), "invalid socket address"); let host = try_opt!(parts_iter.next(), "invalid socket address"); let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value"); diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index fe55f40390e17..ea869ebae100a 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -25,7 +25,7 @@ use string::String; use vec::Vec; /// A flag that specifies whether to use exponential (scientific) notation. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum ExponentFormat { /// Do not use exponential notation. ExpNone, @@ -40,7 +40,7 @@ pub enum ExponentFormat { /// The number of digits used for emitting the fractional part of a number, if /// any. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum SignificantDigits { /// All calculable digits will be printed. /// @@ -57,7 +57,7 @@ pub enum SignificantDigits { } /// How to emit the sign of a number. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum SignFormat { /// No sign will be printed. The exponent sign will also be emitted. SignNone, diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs index 9d7e1082d33b1..98ff6e82c6f7f 100644 --- a/src/libstd/old_io/mod.rs +++ b/src/libstd/old_io/mod.rs @@ -391,7 +391,7 @@ impl Error for IoError { } /// A list specifying general categories of I/O error. -#[derive(Copy, PartialEq, Eq, Clone, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum IoErrorKind { /// Any I/O error not part of this list. OtherIoError, @@ -1553,7 +1553,7 @@ impl BufferPrelude for T { /// When seeking, the resulting cursor is offset from a base by the offset given /// to the `seek` function. The base used is specified by this enumeration. -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum SeekStyle { /// Seek from the beginning of the stream SeekSet, @@ -1744,7 +1744,7 @@ pub enum FileType { /// /// println!("byte size: {}", info.size); /// ``` -#[derive(Copy, Hash)] +#[derive(Copy, Clone, Hash)] pub struct FileStat { /// The size of the file, in bytes pub size: u64, @@ -1783,7 +1783,7 @@ pub struct FileStat { /// structure. This information is not necessarily platform independent, and may /// have different meanings or no meaning at all on some platforms. #[unstable(feature = "io")] -#[derive(Copy, Hash)] +#[derive(Copy, Clone, Hash)] pub struct UnstableFileStat { /// The ID of the device containing the file. pub device: u64, diff --git a/src/libstd/old_io/net/addrinfo.rs b/src/libstd/old_io/net/addrinfo.rs index 739439ebd151b..c5fa775ab4e6f 100644 --- a/src/libstd/old_io/net/addrinfo.rs +++ b/src/libstd/old_io/net/addrinfo.rs @@ -29,7 +29,7 @@ use sys; use vec::Vec; /// Hints to the types of sockets that are desired when looking up hosts -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum SocketType { Stream, Datagram, Raw } @@ -38,7 +38,7 @@ pub enum SocketType { /// to manipulate how a query is performed. /// /// The meaning of each of these flags can be found with `man -s 3 getaddrinfo` -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Flag { AddrConfig, All, @@ -51,7 +51,7 @@ pub enum Flag { /// A transport protocol associated with either a hint or a return value of /// `lookup` -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Protocol { TCP, UDP } @@ -61,7 +61,7 @@ pub enum Protocol { /// /// For details on these fields, see their corresponding definitions via /// `man -s 3 getaddrinfo` -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Hint { pub family: usize, pub socktype: Option, @@ -69,7 +69,7 @@ pub struct Hint { pub flags: usize, } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub struct Info { pub address: SocketAddr, pub family: usize, diff --git a/src/libstd/old_io/util.rs b/src/libstd/old_io/util.rs index a5ecb98334a81..818c8e76d6087 100644 --- a/src/libstd/old_io/util.rs +++ b/src/libstd/old_io/util.rs @@ -90,7 +90,7 @@ impl Buffer for LimitReader { } /// A `Writer` which ignores bytes written to it, like /dev/null. -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[deprecated(since = "1.0.0", reason = "use std::io::sink() instead")] #[unstable(feature = "old_io")] pub struct NullWriter; @@ -103,7 +103,7 @@ impl Writer for NullWriter { } /// A `Reader` which returns an infinite stream of 0 bytes, like /dev/zero. -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[deprecated(since = "1.0.0", reason = "use std::io::repeat(0) instead")] #[unstable(feature = "old_io")] pub struct ZeroReader; @@ -130,7 +130,7 @@ impl Buffer for ZeroReader { } /// A `Reader` which is always at EOF, like /dev/null. -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] #[deprecated(since = "1.0.0", reason = "use std::io::empty() instead")] #[unstable(feature = "old_io")] pub struct NullReader; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 9006ed336542e..4471b5afa84c8 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -343,6 +343,15 @@ impl<'a> Prefix<'a> { /// Determine whether the character is one of the permitted path /// separators for the current platform. +/// +/// # Examples +/// +/// ``` +/// use std::path; +/// +/// assert!(path::is_separator('/')); +/// assert!(!path::is_separator('❤')); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_separator(c: char) -> bool { use ascii::*; @@ -406,7 +415,7 @@ fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { // contents of the encoding and (2) new &OsStr values are produced // only from ASCII-bounded slices of existing &OsStr values. - let mut iter = os_str_as_u8_slice(file).rsplitn(1, |b| *b == b'.'); + let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); let after = iter.next(); let before = iter.next(); if before == Some(b"") { @@ -539,6 +548,18 @@ impl<'a> AsRef for Component<'a> { /// /// See the module documentation for an in-depth explanation of components and /// their role in the API. +/// +/// # Examples +/// +/// ``` +/// use std::path::Path; +/// +/// let path = Path::new("/tmp/foo/bar.txt"); +/// +/// for component in path.components() { +/// println!("{:?}", component); +/// } +/// ``` #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Components<'a> { @@ -609,6 +630,16 @@ impl<'a> Components<'a> { } /// Extract a slice corresponding to the portion of the path remaining for iteration. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo/bar.txt"); + /// + /// println!("{:?}", path.components().as_path()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { let mut comps = self.clone(); @@ -1210,12 +1241,28 @@ impl Path { /// Directly wrap a string slice as a `Path` slice. /// /// This is a cost-free conversion. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// Path::new("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new + ?Sized>(s: &S) -> &Path { unsafe { mem::transmute(s.as_ref()) } } /// Yield the underlying `OsStr` slice. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let os_str = Path::new("foo.txt").as_os_str(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn as_os_str(&self) -> &OsStr { &self.inner @@ -1224,6 +1271,14 @@ impl Path { /// Yield a `&str` slice if the `Path` is valid unicode. /// /// This conversion may entail doing a check for UTF-8 validity. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_str(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() @@ -1232,12 +1287,28 @@ impl Path { /// Convert a `Path` to a `Cow`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_string_lossy(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow { self.inner.to_string_lossy() } /// Convert a `Path` to an owned `PathBuf`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path_str = Path::new("foo.txt").to_path_buf(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_path_buf(&self) -> PathBuf { PathBuf::from(self.inner.to_os_string()) @@ -1251,6 +1322,14 @@ impl Path { /// * On Windows, a path is absolute if it has a prefix and starts with the /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. In /// other words, `path.is_absolute() == path.prefix().is_some() && path.has_root()`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert_eq!(false, Path::new("foo.txt").is_absolute()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_absolute(&self) -> bool { self.has_root() && @@ -1258,6 +1337,14 @@ impl Path { } /// A path is *relative* if it is not absolute. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert!(Path::new("foo.txt").is_relative()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_relative(&self) -> bool { !self.is_absolute() @@ -1281,6 +1368,14 @@ impl Path { /// * has no prefix and begins with a separator, e.g. `\\windows` /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows` /// * has any non-disk prefix, e.g. `\\server\share` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// assert!(Path::new("/etc/passwd").has_root()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn has_root(&self) -> bool { self.components().has_root() @@ -1297,8 +1392,11 @@ impl Path { /// /// let path = Path::new("/foo/bar"); /// let foo = path.parent().unwrap(); + /// /// assert!(foo == Path::new("/foo")); + /// /// let root = foo.parent().unwrap(); + /// /// assert!(root == Path::new("/")); /// assert!(root.parent() == None); /// ``` @@ -1318,6 +1416,17 @@ impl Path { /// /// If the path terminates in `.`, `..`, or consists solely or a root of /// prefix, `file_name` will return `None`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("hello_world.rs"); + /// let filename = "hello_world.rs"; + /// + /// assert_eq!(filename, path.file_name().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { self.components().next_back().and_then(|p| match p { @@ -1337,12 +1446,32 @@ impl Path { } /// Determines whether `base` is a prefix of `self`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/etc/passwd"); + /// + /// assert!(path.starts_with("/etc")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with>(&self, base: P) -> bool { iter_after(self.components(), base.as_ref().components()).is_some() } /// Determines whether `child` is a suffix of `self`. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/etc/passwd"); + /// + /// assert!(path.ends_with("passwd")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn ends_with>(&self, child: P) -> bool { iter_after(self.components().rev(), child.as_ref().components().rev()).is_some() @@ -1356,6 +1485,16 @@ impl Path { /// * The entire file name if there is no embedded `.`; /// * The entire file name if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name before the final `.` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("foo.rs"); + /// + /// assert_eq!("foo", path.file_stem().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_stem(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after)) @@ -1369,6 +1508,16 @@ impl Path { /// * None, if there is no embedded `.`; /// * None, if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name after the final `.` + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("foo.rs"); + /// + /// assert_eq!("rs", path.extension().unwrap()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn extension(&self) -> Option<&OsStr> { self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after)) @@ -1377,6 +1526,16 @@ impl Path { /// Creates an owned `PathBuf` with `path` adjoined to `self`. /// /// See `PathBuf::push` for more details on what it means to adjoin a path. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp"); + /// + /// let new_path = path.join("foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn join>(&self, path: P) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1387,6 +1546,16 @@ impl Path { /// Creates an owned `PathBuf` like `self` but with the given file name. /// /// See `PathBuf::set_file_name` for more details. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// let new_path = path.with_file_name("bar.rs"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_file_name>(&self, file_name: S) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1397,6 +1566,16 @@ impl Path { /// Creates an owned `PathBuf` like `self` but with the given extension. /// /// See `PathBuf::set_extension` for more details. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// let new_path = path.with_extension("foo.txt"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_extension>(&self, extension: S) -> PathBuf { let mut buf = self.to_path_buf(); @@ -1405,6 +1584,18 @@ impl Path { } /// Produce an iterator over the components of the path. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// for component in path.components() { + /// println!("{:?}", component); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn components(&self) -> Components { let prefix = parse_prefix(self.as_os_str()); @@ -1418,6 +1609,18 @@ impl Path { } /// Produce an iterator over the path's components viewed as `OsStr` slices. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// for component in path.iter() { + /// println!("{:?}", component); + /// } + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter { Iter { inner: self.components() } @@ -1425,6 +1628,16 @@ impl Path { /// Returns an object that implements `Display` for safely printing paths /// that may contain non-Unicode data. + /// + /// # Examples + /// + /// ``` + /// use std::path::Path; + /// + /// let path = Path::new("/tmp/foo.rs"); + /// + /// println!("{}", path.display()); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn display(&self) -> Display { Display { path: self } diff --git a/src/libstd/rand/os.rs b/src/libstd/rand/os.rs index 7aba40dc6be89..38c57eec684db 100644 --- a/src/libstd/rand/os.rs +++ b/src/libstd/rand/os.rs @@ -185,9 +185,9 @@ mod imp { mod imp { use prelude::v1::*; + use io; use old_io::IoResult; use mem; - use os; use rand::Rng; use libc::{c_int, size_t}; @@ -241,7 +241,7 @@ mod imp { SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr()) }; if ret == -1 { - panic!("couldn't generate random bytes: {}", os::last_os_error()); + panic!("couldn't generate random bytes: {}", io::Error::last_os_error()); } } } diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 9079c0aaffb7d..beb2870807a7e 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -64,7 +64,7 @@ pub fn cleanup() { if queue as usize != 0 { let queue: Box = Box::from_raw(queue); for to_run in *queue { - to_run.invoke(()); + to_run(); } } } diff --git a/src/libstd/rt/libunwind.rs b/src/libstd/rt/libunwind.rs index b77699105646d..4b754bd5f589f 100644 --- a/src/libstd/rt/libunwind.rs +++ b/src/libstd/rt/libunwind.rs @@ -25,7 +25,7 @@ use libc; #[cfg(any(not(target_arch = "arm"), target_os = "ios"))] #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum _Unwind_Action { _UA_SEARCH_PHASE = 1, _UA_CLEANUP_PHASE = 2, diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 7ea77a7961938..0d26206f26bcf 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -21,7 +21,6 @@ use prelude::v1::*; use sys; -use thunk::Thunk; use usize; // Reexport some of our utilities which are expected by other crates. @@ -153,7 +152,7 @@ fn lang_start(main: *const u8, argc: isize, argv: *const *const u8) -> isize { /// that the closure could not be registered, meaning that it is not scheduled /// to be rune. pub fn at_exit(f: F) -> Result<(), ()> { - if at_exit_imp::push(Thunk::new(f)) {Ok(())} else {Err(())} + if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } /// One-time runtime cleanup. diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index e4927bbd3d274..f71811b1eadf6 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -398,7 +398,7 @@ pub mod eabi { pub struct DISPATCHER_CONTEXT; #[repr(C)] - #[derive(Copy)] + #[derive(Copy, Clone)] pub enum EXCEPTION_DISPOSITION { ExceptionContinueExecution, ExceptionContinueSearch, diff --git a/src/libstd/sync/condvar.rs b/src/libstd/sync/condvar.rs index 69c5267ab69fc..a7d8b287a64c0 100644 --- a/src/libstd/sync/condvar.rs +++ b/src/libstd/sync/condvar.rs @@ -140,33 +140,43 @@ impl Condvar { /// Wait on this condition variable for a notification, timing out after a /// specified duration. /// - /// The semantics of this function are equivalent to `wait()` except that - /// the thread will be blocked for roughly no longer than `dur`. This method - /// should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum amount - /// of time waited to be precisely `dur`. + /// The semantics of this function are equivalent to `wait()` + /// except that the thread will be blocked for roughly no longer + /// than `ms` milliseconds. This method should not be used for + /// precise timing due to anomalies such as preemption or platform + /// differences that may not cause the maximum amount of time + /// waited to be precisely `ms`. /// - /// If the wait timed out, then `false` will be returned. Otherwise if a - /// notification was received then `true` will be returned. + /// The returned boolean is `false` only if the timeout is known + /// to have elapsed. /// /// Like `wait`, the lock specified will be re-acquired when this function /// returns, regardless of whether the timeout elapsed or not. - #[unstable(feature = "std_misc")] - pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) - -> LockResult<(MutexGuard<'a, T>, bool)> { + #[stable(feature = "rust1", since = "1.0.0")] + pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32) + -> LockResult<(MutexGuard<'a, T>, bool)> { unsafe { let me: &'static Condvar = &*(self as *const _); - me.inner.wait_timeout(guard, dur) + me.inner.wait_timeout_ms(guard, ms) } } + /// Deprecated: use `wait_timeout_ms` instead. + #[unstable(feature = "std_misc")] + #[deprecated(since = "1.0.0", reason = "use wait_timeout_ms instead")] + pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>, dur: Duration) + -> LockResult<(MutexGuard<'a, T>, bool)> { + self.wait_timeout_ms(guard, dur.num_milliseconds() as u32) + } + /// Wait on this condition variable for a notification, timing out after a /// specified duration. /// /// The semantics of this function are equivalent to `wait_timeout` except /// that the implementation will repeatedly wait while the duration has not /// passed and the provided function returns `false`. - #[unstable(feature = "std_misc")] + #[unstable(feature = "wait_timeout_with", + reason = "unsure if this API is broadly needed or what form it should take")] pub fn wait_timeout_with<'a, T, F>(&self, guard: MutexGuard<'a, T>, dur: Duration, @@ -235,12 +245,12 @@ impl StaticCondvar { /// See `Condvar::wait_timeout`. #[unstable(feature = "std_misc", reason = "may be merged with Condvar in the future")] - pub fn wait_timeout<'a, T>(&'static self, guard: MutexGuard<'a, T>, dur: Duration) - -> LockResult<(MutexGuard<'a, T>, bool)> { + pub fn wait_timeout_ms<'a, T>(&'static self, guard: MutexGuard<'a, T>, ms: u32) + -> LockResult<(MutexGuard<'a, T>, bool)> { let (poisoned, success) = unsafe { let lock = mutex::guard_lock(&guard); self.verify(lock); - let success = self.inner.wait_timeout(lock, dur); + let success = self.inner.wait_timeout(lock, Duration::milliseconds(ms as i64)); (mutex::guard_poison(&guard).get(), success) }; if poisoned { @@ -275,7 +285,8 @@ impl StaticCondvar { let now = SteadyTime::now(); let consumed = &now - &start; let guard = guard_result.unwrap_or_else(|e| e.into_inner()); - let (new_guard_result, no_timeout) = match self.wait_timeout(guard, dur - consumed) { + let res = self.wait_timeout_ms(guard, (dur - consumed).num_milliseconds() as u32); + let (new_guard_result, no_timeout) = match res { Ok((new_guard, no_timeout)) => (Ok(new_guard), no_timeout), Err(err) => { let (new_guard, no_timeout) = err.into_inner(); @@ -350,6 +361,7 @@ mod tests { use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use thread; use time::Duration; + use u32; #[test] fn smoke() { @@ -418,19 +430,19 @@ mod tests { } #[test] - fn wait_timeout() { + fn wait_timeout_ms() { static C: StaticCondvar = CONDVAR_INIT; static M: StaticMutex = MUTEX_INIT; let g = M.lock().unwrap(); - let (g, _no_timeout) = C.wait_timeout(g, Duration::nanoseconds(1000)).unwrap(); + let (g, _no_timeout) = C.wait_timeout_ms(g, 1).unwrap(); // spurious wakeups mean this isn't necessarily true // assert!(!no_timeout); let _t = thread::spawn(move || { let _g = M.lock().unwrap(); C.notify_one(); }); - let (g, no_timeout) = C.wait_timeout(g, Duration::days(1)).unwrap(); + let (g, no_timeout) = C.wait_timeout_ms(g, u32::MAX).unwrap(); assert!(no_timeout); drop(g); unsafe { C.destroy(); M.destroy(); } diff --git a/src/libstd/sync/future.rs b/src/libstd/sync/future.rs index b2afe28fed46d..2cdde1aca9e68 100644 --- a/src/libstd/sync/future.rs +++ b/src/libstd/sync/future.rs @@ -36,6 +36,7 @@ use core::prelude::*; use core::mem::replace; +use boxed::Box; use self::FutureState::*; use sync::mpsc::{Receiver, channel}; use thunk::Thunk; @@ -84,7 +85,7 @@ impl Future { match replace(&mut self.state, Evaluating) { Forced(_) | Evaluating => panic!("Logic error."), Pending(f) => { - self.state = Forced(f.invoke(())); + self.state = Forced(f()); self.get_ref() } } @@ -114,7 +115,7 @@ impl Future { * function. It is not spawned into another task. */ - Future {state: Pending(Thunk::new(f))} + Future {state: Pending(Box::new(f))} } } diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index e14f32865fa10..c80182ec07d32 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -342,7 +342,7 @@ mod spsc_queue; /// The receiving-half of Rust's channel type. This half can only be owned by /// one task #[stable(feature = "rust1", since = "1.0.0")] -pub struct Receiver { +pub struct Receiver { inner: UnsafeCell>, } @@ -354,14 +354,14 @@ unsafe impl Send for Receiver { } /// whenever `next` is called, waiting for a new message, and `None` will be /// returned when the corresponding channel has hung up. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T:Send+'a> { +pub struct Iter<'a, T: 'a> { rx: &'a Receiver } /// The sending-half of Rust's asynchronous channel type. This half can only be /// owned by one task, but it can be cloned to send to other tasks. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Sender { +pub struct Sender { inner: UnsafeCell>, } @@ -372,7 +372,7 @@ unsafe impl Send for Sender { } /// 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. #[stable(feature = "rust1", since = "1.0.0")] -pub struct SyncSender { +pub struct SyncSender { inner: Arc>>, } @@ -433,7 +433,7 @@ pub enum TrySendError { Disconnected(T), } -enum Flavor { +enum Flavor { Oneshot(Arc>>), Stream(Arc>>), Shared(Arc>>), @@ -441,7 +441,7 @@ enum Flavor { } #[doc(hidden)] -trait UnsafeFlavor { +trait UnsafeFlavor { fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell>; unsafe fn inner_mut<'a>(&'a self) -> &'a mut Flavor { &mut *self.inner_unsafe().get() @@ -450,12 +450,12 @@ trait UnsafeFlavor { &*self.inner_unsafe().get() } } -impl UnsafeFlavor for Sender { +impl UnsafeFlavor for Sender { fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell> { &self.inner } } -impl UnsafeFlavor for Receiver { +impl UnsafeFlavor for Receiver { fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell> { &self.inner } @@ -488,7 +488,7 @@ impl UnsafeFlavor for Receiver { /// println!("{:?}", rx.recv().unwrap()); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub fn channel() -> (Sender, Receiver) { +pub fn channel() -> (Sender, Receiver) { let a = Arc::new(UnsafeCell::new(oneshot::Packet::new())); (Sender::new(Flavor::Oneshot(a.clone())), Receiver::new(Flavor::Oneshot(a))) } @@ -528,7 +528,7 @@ pub fn channel() -> (Sender, Receiver) { /// assert_eq!(rx.recv().unwrap(), 2); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { +pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { let a = Arc::new(UnsafeCell::new(sync::Packet::new(bound))); (SyncSender::new(a.clone()), Receiver::new(Flavor::Sync(a))) } @@ -537,7 +537,7 @@ pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { // Sender //////////////////////////////////////////////////////////////////////////////// -impl Sender { +impl Sender { fn new(inner: Flavor) -> Sender { Sender { inner: UnsafeCell::new(inner), @@ -619,7 +619,7 @@ impl Sender { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Sender { +impl Clone for Sender { fn clone(&self) -> Sender { let (packet, sleeper, guard) = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { @@ -665,7 +665,7 @@ impl Clone for Sender { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Sender { +impl Drop for Sender { fn drop(&mut self) { match *unsafe { self.inner_mut() } { Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_chan(); }, @@ -680,7 +680,7 @@ impl Drop for Sender { // SyncSender //////////////////////////////////////////////////////////////////////////////// -impl SyncSender { +impl SyncSender { fn new(inner: Arc>>) -> SyncSender { SyncSender { inner: inner } } @@ -720,7 +720,7 @@ impl SyncSender { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for SyncSender { +impl Clone for SyncSender { fn clone(&self) -> SyncSender { unsafe { (*self.inner.get()).clone_chan(); } return SyncSender::new(self.inner.clone()); @@ -729,7 +729,7 @@ impl Clone for SyncSender { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for SyncSender { +impl Drop for SyncSender { fn drop(&mut self) { unsafe { (*self.inner.get()).drop_chan(); } } @@ -739,7 +739,7 @@ impl Drop for SyncSender { // Receiver //////////////////////////////////////////////////////////////////////////////// -impl Receiver { +impl Receiver { fn new(inner: Flavor) -> Receiver { Receiver { inner: UnsafeCell::new(inner) } } @@ -858,7 +858,7 @@ impl Receiver { } } -impl select::Packet for Receiver { +impl select::Packet for Receiver { fn can_recv(&self) -> bool { loop { let new_port = match *unsafe { self.inner() } { @@ -945,7 +945,7 @@ impl select::Packet for Receiver { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T: Send> Iterator for Iter<'a, T> { +impl<'a, T> Iterator for Iter<'a, T> { type Item = T; fn next(&mut self) -> Option { self.rx.recv().ok() } @@ -953,7 +953,7 @@ impl<'a, T: Send> Iterator for Iter<'a, T> { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Receiver { +impl Drop for Receiver { fn drop(&mut self) { match *unsafe { self.inner_mut() } { Flavor::Oneshot(ref mut p) => unsafe { (*p.get()).drop_port(); }, diff --git a/src/libstd/sync/mpsc/mpsc_queue.rs b/src/libstd/sync/mpsc/mpsc_queue.rs index 1be8b0dd8628a..9b6c8f4dd9775 100644 --- a/src/libstd/sync/mpsc/mpsc_queue.rs +++ b/src/libstd/sync/mpsc/mpsc_queue.rs @@ -72,12 +72,12 @@ struct Node { /// The multi-producer single-consumer structure. This is not cloneable, but it /// may be safely shared so long as it is guaranteed that there is only one /// popper at a time (many pushers are allowed). -pub struct Queue { +pub struct Queue { head: AtomicPtr>, tail: UnsafeCell<*mut Node>, } -unsafe impl Send for Queue { } +unsafe impl Send for Queue { } unsafe impl Sync for Queue { } impl Node { @@ -89,7 +89,7 @@ impl Node { } } -impl Queue { +impl Queue { /// Creates a new queue that is safe to share among multiple producers and /// one consumer. pub fn new() -> Queue { @@ -140,7 +140,7 @@ impl Queue { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Queue { +impl Drop for Queue { fn drop(&mut self) { unsafe { let mut cur = *self.tail.get(); diff --git a/src/libstd/sync/mpsc/oneshot.rs b/src/libstd/sync/mpsc/oneshot.rs index 13578ce051791..c6e8d87a22e71 100644 --- a/src/libstd/sync/mpsc/oneshot.rs +++ b/src/libstd/sync/mpsc/oneshot.rs @@ -54,7 +54,7 @@ const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded // moves *from* a pointer, ownership of the token is transferred to // whoever changed the state. -pub struct Packet { +pub struct Packet { // Internal state of the chan/port pair (stores the blocked task as well) state: AtomicUsize, // One-shot data slot location @@ -64,7 +64,7 @@ pub struct Packet { upgrade: MyUpgrade, } -pub enum Failure { +pub enum Failure { Empty, Disconnected, Upgraded(Receiver), @@ -76,19 +76,19 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { +pub enum SelectionResult { SelCanceled, SelUpgraded(SignalToken, Receiver), SelSuccess, } -enum MyUpgrade { +enum MyUpgrade { NothingSent, SendUsed, GoUp(Receiver), } -impl Packet { +impl Packet { pub fn new() -> Packet { Packet { data: None, @@ -368,7 +368,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { fn drop(&mut self) { assert_eq!(self.state.load(Ordering::SeqCst), DISCONNECTED); } diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs index 80cbd0761638f..5c1610bdc3175 100644 --- a/src/libstd/sync/mpsc/shared.rs +++ b/src/libstd/sync/mpsc/shared.rs @@ -40,7 +40,7 @@ const MAX_STEALS: isize = 5; #[cfg(not(test))] const MAX_STEALS: isize = 1 << 20; -pub struct Packet { +pub struct Packet { queue: mpsc::Queue, cnt: AtomicIsize, // How many items are on this channel steals: isize, // How many times has a port received without blocking? @@ -64,7 +64,7 @@ pub enum Failure { Disconnected, } -impl Packet { +impl Packet { // Creation of a packet *must* be followed by a call to postinit_lock // and later by inherit_blocker pub fn new() -> Packet { @@ -474,7 +474,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { 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 diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index cd6d1ee05c788..c75ac13080866 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -57,7 +57,7 @@ struct Node { /// but it can be safely shared in an Arc if it is guaranteed that there /// is only one popper and one pusher touching the queue at any one point in /// time. -pub struct Queue { +pub struct Queue { // consumer fields tail: UnsafeCell<*mut Node>, // where to pop from tail_prev: AtomicPtr>, // where to pop from @@ -78,7 +78,7 @@ unsafe impl Send for Queue { } unsafe impl Sync for Queue { } -impl Node { +impl Node { fn new() -> *mut Node { unsafe { boxed::into_raw(box Node { @@ -89,7 +89,7 @@ impl Node { } } -impl Queue { +impl Queue { /// Creates a new queue. /// /// This is unsafe as the type system doesn't enforce a single @@ -227,7 +227,7 @@ impl Queue { } #[unsafe_destructor] -impl Drop for Queue { +impl Drop for Queue { fn drop(&mut self) { unsafe { let mut cur = *self.first.get(); diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index a5a73314a6db3..f0363fae84f73 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -39,7 +39,7 @@ const MAX_STEALS: isize = 5; #[cfg(not(test))] const MAX_STEALS: isize = 1 << 20; -pub struct Packet { +pub struct Packet { queue: spsc::Queue>, // internal queue for all message cnt: AtomicIsize, // How many items are on this channel @@ -49,7 +49,7 @@ pub struct Packet { port_dropped: AtomicBool, // flag if the channel has been destroyed. } -pub enum Failure { +pub enum Failure { Empty, Disconnected, Upgraded(Receiver), @@ -61,7 +61,7 @@ pub enum UpgradeResult { UpWoke(SignalToken), } -pub enum SelectionResult { +pub enum SelectionResult { SelSuccess, SelCanceled, SelUpgraded(SignalToken, Receiver), @@ -69,12 +69,12 @@ pub enum SelectionResult { // Any message could contain an "upgrade request" to a new shared port, so the // internal queue it's a queue of T, but rather Message -enum Message { +enum Message { Data(T), GoUp(Receiver), } -impl Packet { +impl Packet { pub fn new() -> Packet { Packet { queue: unsafe { spsc::Queue::new(128) }, @@ -472,7 +472,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { 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 diff --git a/src/libstd/sync/mpsc/sync.rs b/src/libstd/sync/mpsc/sync.rs index 71236269487ef..6221ca59b54f7 100644 --- a/src/libstd/sync/mpsc/sync.rs +++ b/src/libstd/sync/mpsc/sync.rs @@ -47,7 +47,7 @@ use sync::mpsc::blocking::{self, WaitToken, SignalToken}; use sync::mpsc::select::StartResult::{self, Installed, Abort}; use sync::{Mutex, MutexGuard}; -pub struct Packet { +pub struct Packet { /// Only field outside of the mutex. Just done for kicks, but mainly because /// the other shared channel already had the code implemented channels: AtomicUsize, @@ -113,10 +113,10 @@ pub enum Failure { /// 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>(lock: &'a Mutex>, - mut guard: MutexGuard<'b, State>, - f: fn(SignalToken) -> Blocker) - -> MutexGuard<'a, State> +fn wait<'a, 'b, T>(lock: &'a Mutex>, + mut guard: MutexGuard<'b, State>, + f: fn(SignalToken) -> Blocker) + -> MutexGuard<'a, State> { let (wait_token, signal_token) = blocking::tokens(); match mem::replace(&mut guard.blocker, f(signal_token)) { @@ -136,7 +136,7 @@ fn wakeup(token: SignalToken, guard: MutexGuard>) { token.signal(); } -impl Packet { +impl Packet { pub fn new(cap: usize) -> Packet { Packet { channels: AtomicUsize::new(1), @@ -412,7 +412,7 @@ impl Packet { } #[unsafe_destructor] -impl Drop for Packet { +impl Drop for Packet { fn drop(&mut self) { assert_eq!(self.channels.load(Ordering::SeqCst), 0); let mut guard = self.lock.lock().unwrap(); diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index b24cfbb6899a9..16e7f265412f3 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -112,7 +112,7 @@ use fmt; /// *guard += 1; /// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub struct Mutex { +pub struct Mutex { // Note that this static mutex is in a *box*, not inlined into the struct // itself. Once a native mutex has been used once, its address can never // change (it can't be moved). This mutex type can be safely moved at any @@ -122,6 +122,8 @@ pub struct Mutex { data: UnsafeCell, } +// these are the only places where `T: Send` matters; all other +// functionality works fine on a single thread. unsafe impl Send for Mutex { } unsafe impl Sync for Mutex { } @@ -181,7 +183,7 @@ pub const MUTEX_INIT: StaticMutex = StaticMutex { poison: poison::FLAG_INIT, }; -impl Mutex { +impl Mutex { /// Creates a new mutex in an unlocked state ready for use. #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex { @@ -244,7 +246,7 @@ impl Mutex { #[unsafe_destructor] #[stable(feature = "rust1", since = "1.0.0")] -impl Drop for Mutex { +impl Drop for Mutex { 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 @@ -254,7 +256,7 @@ impl Drop for Mutex { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Mutex { +impl fmt::Debug for Mutex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_lock() { Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", *guard), diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index a79ffaa0860e3..d70350bc7d651 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -130,7 +130,7 @@ pub struct RwLockWriteGuard<'a, T: 'a> { impl<'a, T> !marker::Send for RwLockWriteGuard<'a, T> {} -impl RwLock { +impl RwLock { /// Creates a new instance of an `RwLock` which is unlocked. /// /// # Examples @@ -258,7 +258,7 @@ impl Drop for RwLock { } #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for RwLock { +impl fmt::Debug for RwLock { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_read() { Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", *guard), diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 1a0ee17904a24..fc21effb45a8d 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -115,9 +115,9 @@ pub fn socket(addr: SocketAddr, ty: libc::c_int) -> IoResult { Ipv4Addr(..) => libc::AF_INET, Ipv6Addr(..) => libc::AF_INET6, }; - match libc::socket(fam, ty, 0) { + match libc::socket(fam, ty, 0) as i32 { -1 => Err(last_net_error()), - fd => Ok(fd), + fd => Ok(fd as sock_t), } } } diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs index f45daea18a21f..1845b6266ed8d 100644 --- a/src/libstd/sys/common/thread.rs +++ b/src/libstd/sys/common/thread.rs @@ -25,6 +25,7 @@ pub fn start_thread(main: *mut libc::c_void) { unsafe { stack::record_os_managed_stack_bounds(0, usize::MAX); let _handler = stack_overflow::Handler::new(); - Box::from_raw(main as *mut Thunk).invoke(()); + let main: Box = Box::from_raw(main as *mut Thunk); + main(); } } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 7b13e951b9b33..d2220bdec32b7 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -409,7 +409,7 @@ pub fn env() -> Env { }; fn parse(input: &[u8]) -> (OsString, OsString) { - let mut it = input.splitn(1, |b| *b == b'='); + let mut it = input.splitn(2, |b| *b == b'='); let key = it.next().unwrap().to_vec(); let default: &[u8] = &[]; let val = it.next().unwrap_or(default).to_vec(); diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index e74de595f9750..4804f6504419c 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -49,9 +49,9 @@ pub const ERROR_NO_MORE_FILES: libc::DWORD = 18; pub const TOKEN_READ: libc::DWORD = 0x20008; // Note that these are not actually HANDLEs, just values to pass to GetStdHandle -pub const STD_INPUT_HANDLE: libc::DWORD = -10; -pub const STD_OUTPUT_HANDLE: libc::DWORD = -11; -pub const STD_ERROR_HANDLE: libc::DWORD = -12; +pub const STD_INPUT_HANDLE: libc::DWORD = -10i32 as libc::DWORD; +pub const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD; +pub const STD_ERROR_HANDLE: libc::DWORD = -12i32 as libc::DWORD; #[repr(C)] #[cfg(target_arch = "x86")] @@ -89,7 +89,6 @@ pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; pub type WSAEVENT = libc::HANDLE; #[repr(C)] -#[derive(Copy)] pub struct WSAPROTOCOL_INFO { pub dwServiceFlags1: libc::DWORD, pub dwServiceFlags2: libc::DWORD, diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs index 2ac8ac10aa9ae..41e97dc847502 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -15,6 +15,7 @@ use prelude::v1::*; use old_io::net::ip; use old_io::IoResult; use libc; +use libc::consts::os::extra::INVALID_SOCKET; use mem; use ptr; use super::{last_error, last_net_error, sock_t}; @@ -183,8 +184,8 @@ impl TcpAcceptor { match unsafe { libc::accept(self.socket(), ptr::null_mut(), ptr::null_mut()) } { - -1 if wouldblock() => {} - -1 => return Err(last_net_error()), + INVALID_SOCKET if wouldblock() => {} + INVALID_SOCKET => return Err(last_net_error()), // Accepted sockets inherit the same properties as the caller, // so we need to deregister our event and switch the socket back diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index b9cbd01bed180..acd6970f11373 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -197,7 +197,7 @@ macro_rules! __thread_local_inner { /// Indicator of the state of a thread local storage key. #[unstable(feature = "std_misc", reason = "state querying was recently added")] -#[derive(Eq, PartialEq, Copy)] +#[derive(Eq, PartialEq, Copy, Clone)] pub enum LocalKeyState { /// All keys are in this state whenever a thread starts. Keys will /// transition to the `Valid` state once the first call to `with` happens diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 1202b353317cd..5fe6e80d6e93a 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -257,7 +257,7 @@ impl Builder { pub fn spawn(self, f: F) -> io::Result where F: FnOnce(), F: Send + 'static { - self.spawn_inner(Thunk::new(f)).map(|i| JoinHandle(i)) + self.spawn_inner(Box::new(f)).map(|i| JoinHandle(i)) } /// Spawn a new child thread that must be joined within a given @@ -279,7 +279,7 @@ impl Builder { pub fn scoped<'a, T, F>(self, f: F) -> io::Result> where T: Send + 'a, F: FnOnce() -> T, F: Send + 'a { - self.spawn_inner(Thunk::new(f)).map(|inner| { + self.spawn_inner(Box::new(f)).map(|inner| { JoinGuard { inner: inner, _marker: PhantomData } }) } @@ -315,7 +315,7 @@ impl Builder { thread_info::set(imp::guard::current(), their_thread); } - let mut output = None; + let mut output: Option = None; let try_result = { let ptr = &mut output; @@ -327,7 +327,11 @@ impl Builder { // 'unwinding' flag in the thread itself. For these reasons, // this unsafety should be ok. unsafe { - unwind::try(move || *ptr = Some(f.invoke(()))) + unwind::try(move || { + let f: Thunk<(), T> = f; + let v: T = f(); + *ptr = Some(v) + }) } }; unsafe { @@ -340,7 +344,7 @@ impl Builder { }; Ok(JoinInner { - native: try!(unsafe { imp::create(stack_size, Thunk::new(main)) }), + native: try!(unsafe { imp::create(stack_size, Box::new(main)) }), thread: my_thread, packet: my_packet, joined: false, @@ -465,9 +469,16 @@ pub fn catch_panic(f: F) -> Result /// specifics or platform-dependent functionality. Note that on unix platforms /// this function will not return early due to a signal being received or a /// spurious wakeup. +#[stable(feature = "rust1", since = "1.0.0")] +pub fn sleep_ms(ms: u32) { + imp::sleep(Duration::milliseconds(ms as i64)) +} + +/// Deprecated: use `sleep_ms` instead. #[unstable(feature = "thread_sleep", reason = "recently added, needs an RFC, and `Duration` itself is \ unstable")] +#[deprecated(since = "1.0.0", reason = "use sleep_ms instead")] pub fn sleep(dur: Duration) { imp::sleep(dur) } @@ -501,17 +512,24 @@ pub fn park() { /// amount of time waited to be precisely *duration* long. /// /// See the module doc for more detail. -#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")] -pub fn park_timeout(duration: Duration) { +#[stable(feature = "rust1", since = "1.0.0")] +pub fn park_timeout_ms(ms: u32) { let thread = current(); let mut guard = thread.inner.lock.lock().unwrap(); if !*guard { - let (g, _) = thread.inner.cvar.wait_timeout(guard, duration).unwrap(); + let (g, _) = thread.inner.cvar.wait_timeout_ms(guard, ms).unwrap(); guard = g; } *guard = false; } +/// Deprecated: use `park_timeout_ms` +#[unstable(feature = "std_misc", reason = "recently introduced, depends on Duration")] +#[deprecated(since = "1.0.0", reason = "use park_timeout_ms instead")] +pub fn park_timeout(duration: Duration) { + park_timeout_ms(duration.num_milliseconds() as u32) +} + //////////////////////////////////////////////////////////////////////////////// // Thread //////////////////////////////////////////////////////////////////////////////// @@ -716,6 +734,7 @@ mod test { use thread; use thunk::Thunk; use time::Duration; + use u32; // !!! These tests are dangerous. If something is buggy, they will hang, !!! // !!! instead of exiting cleanly. This might wedge the buildbots. !!! @@ -820,7 +839,7 @@ mod test { let x: Box<_> = box 1; let x_in_parent = (&*x) as *const i32 as usize; - spawnfn(Thunk::new(move|| { + spawnfn(Box::new(move|| { let x_in_child = (&*x) as *const i32 as usize; tx.send(x_in_child).unwrap(); })); @@ -832,7 +851,7 @@ mod test { #[test] fn test_avoid_copying_the_body_spawn() { avoid_copying_the_body(|v| { - thread::spawn(move || v.invoke(())); + thread::spawn(move || v()); }); } @@ -840,7 +859,7 @@ mod test { fn test_avoid_copying_the_body_thread_spawn() { avoid_copying_the_body(|f| { thread::spawn(move|| { - f.invoke(()); + f(); }); }) } @@ -849,7 +868,7 @@ mod test { fn test_avoid_copying_the_body_join() { avoid_copying_the_body(|f| { let _ = thread::spawn(move|| { - f.invoke(()) + f() }).join(); }) } @@ -862,13 +881,13 @@ mod test { // valgrind-friendly. try this at home, instead..!) const GENERATIONS: u32 = 16; fn child_no(x: u32) -> Thunk<'static> { - return Thunk::new(move|| { + return Box::new(move|| { if x < GENERATIONS { - thread::spawn(move|| child_no(x+1).invoke(())); + thread::spawn(move|| child_no(x+1)()); } }); } - thread::spawn(|| child_no(0).invoke(())); + thread::spawn(|| child_no(0)()); } #[test] @@ -936,14 +955,14 @@ mod test { fn test_park_timeout_unpark_before() { for _ in 0..10 { thread::current().unpark(); - thread::park_timeout(Duration::seconds(10_000_000)); + thread::park_timeout_ms(u32::MAX); } } #[test] fn test_park_timeout_unpark_not_called() { for _ in 0..10 { - thread::park_timeout(Duration::milliseconds(10)); + thread::park_timeout_ms(10); } } @@ -959,14 +978,13 @@ mod test { th.unpark(); }); - thread::park_timeout(Duration::seconds(10_000_000)); + thread::park_timeout_ms(u32::MAX); } } #[test] - fn sleep_smoke() { - thread::sleep(Duration::milliseconds(2)); - thread::sleep(Duration::milliseconds(-2)); + fn sleep_ms_smoke() { + thread::sleep_ms(2); } // NOTE: the corresponding test for stderr is in run-pass/task-stderr, due diff --git a/src/libstd/thunk.rs b/src/libstd/thunk.rs index a9cb05b368f02..6091794ed4286 100644 --- a/src/libstd/thunk.rs +++ b/src/libstd/thunk.rs @@ -12,45 +12,9 @@ #![allow(missing_docs)] #![unstable(feature = "std_misc")] -use alloc::boxed::Box; +use alloc::boxed::{Box, FnBox}; use core::marker::Send; -use core::ops::FnOnce; -pub struct Thunk<'a, A=(),R=()> { - invoke: Box+Send + 'a>, -} +pub type Thunk<'a, A=(), R=()> = + Box + Send + 'a>; -impl<'a, R> Thunk<'a,(),R> { - pub fn new(func: F) -> Thunk<'a,(),R> - where F : FnOnce() -> R, F : Send + 'a - { - Thunk::with_arg(move|()| func()) - } -} - -impl<'a,A,R> Thunk<'a,A,R> { - pub fn with_arg(func: F) -> Thunk<'a,A,R> - where F : FnOnce(A) -> R, F : Send + 'a - { - Thunk { - invoke: Box::::new(func) - } - } - - pub fn invoke(self, arg: A) -> R { - self.invoke.invoke(arg) - } -} - -pub trait Invoke { - fn invoke(self: Box, arg: A) -> R; -} - -impl Invoke for F - where F : FnOnce(A) -> R -{ - fn invoke(self: Box, arg: A) -> R { - let f = *self; - f(arg) - } -} diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 896e638deb465..27e331893e5d7 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -15,7 +15,7 @@ pub use self::AbiArchitecture::*; use std::fmt; -#[derive(Copy, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum Os { OsWindows, OsMacos, @@ -49,7 +49,7 @@ pub enum Abi { } #[allow(non_camel_case_types)] -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub enum Architecture { X86, X86_64, @@ -58,7 +58,7 @@ pub enum Architecture { Mipsel } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct AbiData { abi: Abi, @@ -66,7 +66,7 @@ pub struct AbiData { name: &'static str, } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum AbiArchitecture { /// Not a real ABI (e.g., intrinsic) RustArch, diff --git a/src/libsyntax/ast_map/blocks.rs b/src/libsyntax/ast_map/blocks.rs index 1994ca70bbbb4..475970ac30a75 100644 --- a/src/libsyntax/ast_map/blocks.rs +++ b/src/libsyntax/ast_map/blocks.rs @@ -40,7 +40,7 @@ use visit; /// - The default implementation for a trait method. /// /// To construct one, use the `Code::from_node` function. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct FnLikeNode<'a> { node: ast_map::Node<'a> } /// MaybeFnLike wraps a method that indicates if an object @@ -80,7 +80,7 @@ impl MaybeFnLike for ast::Expr { /// Carries either an FnLikeNode or a Block, as these are the two /// constructs that correspond to "code" (as in, something from which /// we can construct a control-flow graph). -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Code<'a> { FnLikeCode(FnLikeNode<'a>), BlockCode(&'a Block), diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index 48bb044cb1854..2a9a609ecd1e9 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -53,18 +53,29 @@ impl fmt::Display for PathElem { } #[derive(Clone)] -struct LinkedPathNode<'a> { +pub struct LinkedPathNode<'a> { node: PathElem, next: LinkedPath<'a>, } -type LinkedPath<'a> = Option<&'a LinkedPathNode<'a>>; +#[derive(Copy, Clone)] +pub struct LinkedPath<'a>(Option<&'a LinkedPathNode<'a>>); + +impl<'a> LinkedPath<'a> { + pub fn empty() -> LinkedPath<'a> { + LinkedPath(None) + } + + pub fn from(node: &'a LinkedPathNode) -> LinkedPath<'a> { + LinkedPath(Some(node)) + } +} impl<'a> Iterator for LinkedPath<'a> { type Item = PathElem; fn next(&mut self) -> Option { - match *self { + match self.0 { Some(node) => { *self = node.next; Some(node.node) @@ -90,7 +101,7 @@ pub fn path_to_string>(path: PI) -> String { }) } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] pub enum Node<'ast> { NodeItem(&'ast Item), NodeForeignItem(&'ast ForeignItem), @@ -384,7 +395,7 @@ impl<'ast> Map<'ast> { pub fn with_path(&self, id: NodeId, f: F) -> T where F: FnOnce(PathElems) -> T, { - self.with_path_next(id, None, f) + self.with_path_next(id, LinkedPath::empty(), f) } pub fn path_to_string(&self, id: NodeId) -> String { @@ -422,7 +433,7 @@ impl<'ast> Map<'ast> { _ => f([].iter().cloned().chain(next)) } } else { - self.with_path_next(parent, Some(&LinkedPathNode { + self.with_path_next(parent, LinkedPath::from(&LinkedPathNode { node: self.get_path_elem(id), next: next }), f) diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index b83b42c73e708..c4c2249d02959 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -291,7 +291,7 @@ pub fn empty_generics() -> Generics { // ______________________________________________________________________ // Enumerating the IDs which appear in an AST -#[derive(RustcEncodable, RustcDecodable, Debug, Copy)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] pub struct IdRange { pub min: NodeId, pub max: NodeId, diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2d8484e95bbc9..06e447bb12af4 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -282,7 +282,7 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option { first_attr_value_str_by_name(attrs, "crate_name") } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum InlineAttr { None, Hint, @@ -571,7 +571,7 @@ fn int_type_of_word(s: &str) -> Option { } } -#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy)] +#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] pub enum ReprAttr { ReprAny, ReprInt(Span, IntType), @@ -590,7 +590,7 @@ impl ReprAttr { } } -#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy)] +#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)] pub enum IntType { SignedInt(ast::IntTy), UnsignedInt(ast::UintTy) diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index c2f2c51ed2cff..b563a5e7d6e84 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -47,7 +47,7 @@ pub struct BytePos(pub u32); /// A character offset. Because of multibyte utf8 characters, a byte offset /// is not equivalent to a character offset. The CodeMap will convert BytePos /// values to CharPos values as necessary. -#[derive(Copy, PartialEq, Hash, PartialOrd, Debug)] +#[derive(Copy, Clone, PartialEq, Hash, PartialOrd, Debug)] pub struct CharPos(pub usize); // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix @@ -305,7 +305,7 @@ pub struct FileLines { } /// Identifies an offset of a multi-byte character in a FileMap -#[derive(Copy, RustcEncodable, RustcDecodable, Eq, PartialEq)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Eq, PartialEq)] pub struct MultiByteChar { /// The absolute offset of the character in the CodeMap pub pos: BytePos, diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 32857769acf4a..f35cc8c8d2399 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -71,12 +71,12 @@ pub trait Emitter { /// This structure is used to signify that a task has panicked with a fatal error /// from the diagnostics. You can use this with the `Any` trait to figure out /// how a rustc task died (if so desired). -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct FatalError; /// Signifies that the compiler died with an explicit call to `.bug` /// or `.span_bug` rather than a failed assertion, etc. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct ExplicitBug; /// A span-handler is like a handler but also @@ -371,7 +371,7 @@ fn stderr_isatty() -> bool { } #[cfg(windows)] fn stderr_isatty() -> bool { - const STD_ERROR_HANDLE: libc::DWORD = -12; + const STD_ERROR_HANDLE: libc::DWORD = -12i32 as libc::DWORD; extern "system" { fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE; fn GetConsoleMode(hConsoleHandle: libc::HANDLE, diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index b679456b3537b..71fba789ff835 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -318,7 +318,7 @@ impl MacResult for MacEager { /// Fill-in macro expansion result, to allow compilation to continue /// after hitting errors. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct DummyResult { expr_only: bool, span: Span diff --git a/src/libsyntax/ext/deriving/cmp/ord.rs b/src/libsyntax/ext/deriving/cmp/ord.rs index b2b2654801863..8ecd172b2f0d8 100644 --- a/src/libsyntax/ext/deriving/cmp/ord.rs +++ b/src/libsyntax/ext/deriving/cmp/ord.rs @@ -84,7 +84,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, trait_def.expand(cx, mitem, item, push) } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum OrderingOp { PartialCmpOp, LtOp, LeOp, GtOp, GeOp, } diff --git a/src/libsyntax/ext/mtwt.rs b/src/libsyntax/ext/mtwt.rs index a2023d6832efb..f514f72d56548 100644 --- a/src/libsyntax/ext/mtwt.rs +++ b/src/libsyntax/ext/mtwt.rs @@ -38,7 +38,7 @@ pub struct SCTable { rename_memo: RefCell>, } -#[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)] +#[derive(PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy, Clone)] pub enum SyntaxContext_ { EmptyCtxt, Mark (Mrk,SyntaxContext), diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index adcef07e19032..dbddd9dd44d0e 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -25,7 +25,7 @@ use self::Status::*; use self::AttributeType::*; -use abi::RustIntrinsic; +use abi::Abi; use ast::NodeId; use ast; use attr; @@ -91,6 +91,8 @@ const KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[ ("start", "1.0.0", Active), ("main", "1.0.0", Active), + ("fundamental", "1.0.0", Active), + // Deprecate after snapshot // SNAP 5520801 ("unsafe_destructor", "1.0.0", Active), @@ -240,6 +242,10 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("allow_internal_unstable", Gated("allow_internal_unstable", EXPLAIN_ALLOW_INTERNAL_UNSTABLE)), + ("fundamental", Gated("fundamental", + "the `#[fundamental]` attribute \ + is an experimental feature")), + // FIXME: #14408 whitelist docs since rustdoc looks at them ("doc", Whitelisted), @@ -289,7 +295,7 @@ pub const KNOWN_ATTRIBUTES: &'static [(&'static str, AttributeType)] = &[ ("recursion_limit", CrateLevel), ]; -#[derive(PartialEq, Copy, Debug)] +#[derive(PartialEq, Copy, Clone, Debug)] pub enum AttributeType { /// Normal, builtin attribute that is consumed /// by the compiler before the unused_attribute check @@ -516,7 +522,7 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { across platforms, it is recommended to \ use `#[link(name = \"foo\")]` instead") } - if foreign_module.abi == RustIntrinsic { + if foreign_module.abi == Abi::RustIntrinsic { self.gate_feature("intrinsics", i.span, "intrinsics are subject to change") @@ -632,11 +638,17 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> { span: Span, _node_id: NodeId) { match fn_kind { - visit::FkItemFn(_, _, _, abi) if abi == RustIntrinsic => { + visit::FkItemFn(_, _, _, abi) if abi == Abi::RustIntrinsic => { self.gate_feature("intrinsics", span, "intrinsics are subject to change") } + visit::FkItemFn(_, _, _, abi) | + visit::FkMethod(_, &ast::MethodSig { abi, .. }) if abi == Abi::RustCall => { + self.gate_feature("unboxed_closures", + span, + "rust-call ABI is subject to change") + } _ => {} } visit::walk_fn(self, fn_kind, fn_decl, block, span); diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index bb9b586bb3f3d..f120dde8e1cb6 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -20,7 +20,7 @@ use parse::token; use ptr::P; /// The specific types of unsupported syntax -#[derive(Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] pub enum ObsoleteSyntax { ClosureKind, ExternCrateString, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 6f1f73aa2a9c5..c721624323923 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -96,7 +96,7 @@ type ItemInfo = (Ident, Item_, Option >); /// How to parse a path. There are four different kinds of paths, all of which /// are parsed somewhat differently. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum PathParsingMode { /// A path with no type parameters; e.g. `foo::bar::Baz` NoTypesAllowed, @@ -109,7 +109,7 @@ pub enum PathParsingMode { } /// How to parse a bound, whether to allow bound modifiers such as `?`. -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] pub enum BoundParsingMode { Bare, Modified, diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index 640b7d1c91d50..ebfd970f3dbfc 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -147,13 +147,13 @@ pub fn buf_str(toks: &[Token], s } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum PrintStackBreak { Fits, Broken(Breaks), } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct PrintStackElem { offset: isize, pbreak: PrintStackBreak diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 3a41b74fb7911..46d196d13fa72 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -37,6 +37,7 @@ pub enum AnnNode<'a> { NodeName(&'a ast::Name), NodeBlock(&'a ast::Block), NodeItem(&'a ast::Item), + NodeSubItem(ast::NodeId), NodeExpr(&'a ast::Expr), NodePat(&'a ast::Pat), } @@ -46,12 +47,12 @@ pub trait PpAnn { fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { Ok(()) } } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct NoAnn; impl PpAnn for NoAnn {} -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct CurrentCommentAndLiteral { cur_cmnt: usize, cur_lit: usize, @@ -1264,6 +1265,7 @@ impl<'a> State<'a> { pub fn print_trait_item(&mut self, ti: &ast::TraitItem) -> io::Result<()> { + try!(self.ann.pre(self, NodeSubItem(ti.id))); try!(self.hardbreak_if_not_bol()); try!(self.maybe_print_comment(ti.span.lo)); try!(self.print_outer_attributes(&ti.attrs)); @@ -1275,19 +1277,21 @@ impl<'a> State<'a> { try!(self.print_method_sig(ti.ident, sig, ast::Inherited)); if let Some(ref body) = *body { try!(self.nbsp()); - self.print_block_with_attrs(body, &ti.attrs) + try!(self.print_block_with_attrs(body, &ti.attrs)); } else { - word(&mut self.s, ";") + try!(word(&mut self.s, ";")); } } ast::TypeTraitItem(ref bounds, ref default) => { - self.print_associated_type(ti.ident, Some(bounds), - default.as_ref().map(|ty| &**ty)) + try!(self.print_associated_type(ti.ident, Some(bounds), + default.as_ref().map(|ty| &**ty))); } } + self.ann.post(self, NodeSubItem(ti.id)) } pub fn print_impl_item(&mut self, ii: &ast::ImplItem) -> io::Result<()> { + try!(self.ann.pre(self, NodeSubItem(ii.id))); try!(self.hardbreak_if_not_bol()); try!(self.maybe_print_comment(ii.span.lo)); try!(self.print_outer_attributes(&ii.attrs)); @@ -1296,10 +1300,10 @@ impl<'a> State<'a> { try!(self.head("")); try!(self.print_method_sig(ii.ident, sig, ii.vis)); try!(self.nbsp()); - self.print_block_with_attrs(body, &ii.attrs) + try!(self.print_block_with_attrs(body, &ii.attrs)); } ast::TypeImplItem(ref ty) => { - self.print_associated_type(ii.ident, None, Some(ty)) + try!(self.print_associated_type(ii.ident, None, Some(ty))); } ast::MacImplItem(codemap::Spanned { node: ast::MacInvocTT(ref pth, ref tts, _), ..}) => { @@ -1311,9 +1315,10 @@ impl<'a> State<'a> { try!(self.print_tts(&tts[..])); try!(self.pclose()); try!(word(&mut self.s, ";")); - self.end() + try!(self.end()) } } + self.ann.post(self, NodeSubItem(ii.id)) } pub fn print_outer_attributes(&mut self, diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 638ddd3ea2e5b..5c345c75642b8 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -32,7 +32,7 @@ use codemap::Span; use ptr::P; use owned_slice::OwnedSlice; -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum FnKind<'a> { /// fn foo() or extern "Abi" fn foo() FkItemFn(Ident, &'a Generics, Unsafety, Abi), diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index 38d58f042b941..74ec3406f73bc 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -184,7 +184,7 @@ pub mod attr { /// Most attributes can only be turned on and must be turned off with term.reset(). /// The ones that can be turned off explicitly take a boolean value. /// Color is also represented as an attribute for convenience. - #[derive(Copy)] + #[derive(Copy, Clone)] pub enum Attr { /// Bold (or possibly bright) mode Bold, diff --git a/src/libterm/terminfo/parm.rs b/src/libterm/terminfo/parm.rs index d6a4659c45a89..01586b8f36ed0 100644 --- a/src/libterm/terminfo/parm.rs +++ b/src/libterm/terminfo/parm.rs @@ -18,7 +18,7 @@ use std::ascii::OwnedAsciiExt; use std::mem::replace; use std::iter::repeat; -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum States { Nothing, Percent, @@ -35,7 +35,7 @@ enum States { SeekIfEndPercent(isize) } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] enum FormatState { FormatStateFlags, FormatStateWidth, @@ -444,7 +444,7 @@ pub fn expand(cap: &[u8], params: &[Param], vars: &mut Variables) Ok(output) } -#[derive(Copy, PartialEq)] +#[derive(Copy, Clone, PartialEq)] struct Flags { width: usize, precision: usize, @@ -461,7 +461,7 @@ impl Flags { } } -#[derive(Copy)] +#[derive(Copy, Clone)] enum FormatOp { FormatDigit, FormatOctal, diff --git a/src/libterm/win.rs b/src/libterm/win.rs index 001313db6769f..66ef5e8661797 100644 --- a/src/libterm/win.rs +++ b/src/libterm/win.rs @@ -104,7 +104,7 @@ impl WinConsole { // terminal! Admittedly, this is fragile, since stderr could be // redirected to a different console. This is good enough for // rustc though. See #13400. - let out = GetStdHandle(-11); + let out = GetStdHandle(-11i32 as libc::DWORD); SetConsoleTextAttribute(out, accum); } } @@ -116,7 +116,8 @@ impl WinConsole { let bg; unsafe { let mut buffer_info = ::std::mem::uninitialized(); - if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 { + if GetConsoleScreenBufferInfo(GetStdHandle(-11i32 as libc::DWORD), + &mut buffer_info) != 0 { fg = bits_to_color(buffer_info.wAttributes); bg = bits_to_color(buffer_info.wAttributes >> 4); } else { diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs index f7e5c9f1deedc..c84703b93ed26 100644 --- a/src/libtest/lib.rs +++ b/src/libtest/lib.rs @@ -62,6 +62,7 @@ use self::OutputLocation::*; use stats::Stats; use getopts::{OptGroup, optflag, optopt}; use serialize::Encodable; +use std::boxed::FnBox; use term::Terminal; use term::color::{Color, RED, YELLOW, GREEN, CYAN}; @@ -79,7 +80,7 @@ use std::path::PathBuf; use std::sync::mpsc::{channel, Sender}; use std::sync::{Arc, Mutex}; use std::thread; -use std::thunk::{Thunk, Invoke}; +use std::thunk::Thunk; use std::time::Duration; // to be used by rustc to compile tests in libtest @@ -158,7 +159,7 @@ pub enum TestFn { StaticBenchFn(fn(&mut Bencher)), StaticMetricFn(fn(&mut MetricMap)), DynTestFn(Thunk<'static>), - DynMetricFn(Box Invoke<&'a mut MetricMap>+'static>), + DynMetricFn(Box), DynBenchFn(Box) } @@ -193,7 +194,7 @@ impl fmt::Debug for TestFn { /// This is fed into functions marked with `#[bench]` to allow for /// set-up & tear-down before running a piece of code repeatedly via a /// call to `iter`. -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Bencher { iterations: u64, dur: Duration, @@ -280,7 +281,7 @@ pub fn test_main_static(args: env::Args, tests: &[TestDescAndFn]) { test_main(&args, owned_tests) } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum ColorConfig { AutoColor, AlwaysColor, @@ -756,7 +757,7 @@ fn stdout_isatty() -> bool { } #[cfg(windows)] fn stdout_isatty() -> bool { - const STD_OUTPUT_HANDLE: libc::DWORD = -11; + const STD_OUTPUT_HANDLE: libc::DWORD = -11i32 as libc::DWORD; extern "system" { fn GetStdHandle(which: libc::DWORD) -> libc::HANDLE; fn GetConsoleMode(hConsoleHandle: libc::HANDLE, @@ -936,7 +937,7 @@ pub fn run_test(opts: &TestOpts, io::set_print(box Sink(data2.clone())); io::set_panic(box Sink(data2)); } - testfn.invoke(()) + testfn() }).unwrap(); let test_result = calc_result(&desc, result_guard.join()); let stdout = data.lock().unwrap().to_vec(); @@ -957,7 +958,7 @@ pub fn run_test(opts: &TestOpts, } DynMetricFn(f) => { let mut mm = MetricMap::new(); - f.invoke(&mut mm); + f.call_box((&mut mm,)); monitor_ch.send((desc, TrMetrics(mm), Vec::new())).unwrap(); return; } @@ -969,7 +970,7 @@ pub fn run_test(opts: &TestOpts, } DynTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, f), StaticTestFn(f) => run_test_inner(desc, monitor_ch, opts.nocapture, - Thunk::new(move|| f())) + Box::new(move|| f())) } } @@ -1185,7 +1186,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1202,7 +1203,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1219,7 +1220,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(None) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1236,7 +1237,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(Some("error message")) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1253,7 +1254,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(Some("foobar")) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1270,7 +1271,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::Yes(None) }, - testfn: DynTestFn(Thunk::new(move|| f())), + testfn: DynTestFn(Box::new(move|| f())), }; let (tx, rx) = channel(); run_test(&TestOpts::new(), false, desc, tx); @@ -1306,7 +1307,7 @@ mod tests { ignore: true, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| {})), + testfn: DynTestFn(Box::new(move|| {})), }, TestDescAndFn { desc: TestDesc { @@ -1314,7 +1315,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(move|| {})), + testfn: DynTestFn(Box::new(move|| {})), }); let filtered = filter_tests(&opts, tests); @@ -1350,7 +1351,7 @@ mod tests { ignore: false, should_panic: ShouldPanic::No, }, - testfn: DynTestFn(Thunk::new(testfn)), + testfn: DynTestFn(Box::new(testfn)), }; tests.push(test); } diff --git a/src/snapshots.txt b/src/snapshots.txt index 74d8b222c541f..5d265478b64da 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,5 +1,5 @@ S 2015-03-27 5520801 - bitrig-x86_64 41de2c7a69a1ac648d3fa3b65e96a29bdc122163 + bitrig-x86_64 55a69b0ae5481ccda54c2fcfc54025a0945c4f57 freebsd-x86_64 0910bbad35e213f679d0433884fd51398eb3bc8d linux-i386 1ef82402ed16f5a6d2f87a9a62eaa83170e249ec linux-x86_64 ef2154372e97a3cb687897d027fd51c8f2c5f349 @@ -9,7 +9,7 @@ S 2015-03-27 5520801 winnt-x86_64 903a99a58f57a9bd9848cc68a2445dda881f1ee8 S 2015-03-25 a923278 - bitrig-x86_64 41de2c7a69a1ac648d3fa3b65e96a29bdc122163 + bitrig-x86_64 e56c400a04bca7b52ab54e0780484bb68fa449c2 freebsd-x86_64 cd02c86a9218da73b2a45aff293787010d33bf3e linux-i386 da50141558eed6dabab97b79b2c6a7de4f2d2c5e linux-x86_64 bca03458d28d07506bad4b80e5770b2117286244 diff --git a/src/test/auxiliary/coherence_copy_like_lib.rs b/src/test/auxiliary/coherence_copy_like_lib.rs new file mode 100644 index 0000000000000..a1e1b48c2c4e9 --- /dev/null +++ b/src/test/auxiliary/coherence_copy_like_lib.rs @@ -0,0 +1,22 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![crate_type = "rlib"] +#![feature(fundamental)] + +use std::marker::MarkerTrait; + +pub trait MyCopy : MarkerTrait { } +impl MyCopy for i32 { } + +pub struct MyStruct(T); + +#[fundamental] +pub struct MyFundamentalStruct(T); diff --git a/src/test/auxiliary/issue-14422.rs b/src/test/auxiliary/issue-14422.rs index 3e23698397b4f..32af6d9255e5b 100644 --- a/src/test/auxiliary/issue-14422.rs +++ b/src/test/auxiliary/issue-14422.rs @@ -23,7 +23,7 @@ mod src { pub mod hidden_core { use super::aliases::B; - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct A; pub fn make() -> B { A } diff --git a/src/test/auxiliary/issue13213aux.rs b/src/test/auxiliary/issue13213aux.rs index c2acc51434615..d0566a1e0914b 100644 --- a/src/test/auxiliary/issue13213aux.rs +++ b/src/test/auxiliary/issue13213aux.rs @@ -13,13 +13,13 @@ pub use private::P; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct S { p: P, } mod private { - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct P { p: i32, } diff --git a/src/test/auxiliary/method_self_arg1.rs b/src/test/auxiliary/method_self_arg1.rs index 643442363a446..348b71faf0cdb 100644 --- a/src/test/auxiliary/method_self_arg1.rs +++ b/src/test/auxiliary/method_self_arg1.rs @@ -17,7 +17,7 @@ static mut COUNT: u64 = 1; pub fn get_count() -> u64 { unsafe { COUNT } } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Foo; impl Foo { diff --git a/src/test/auxiliary/method_self_arg2.rs b/src/test/auxiliary/method_self_arg2.rs index fd99da87e6b0d..b67ec1b9bfc65 100644 --- a/src/test/auxiliary/method_self_arg2.rs +++ b/src/test/auxiliary/method_self_arg2.rs @@ -17,7 +17,7 @@ static mut COUNT: u64 = 1; pub fn get_count() -> u64 { unsafe { COUNT } } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Foo; impl Foo { diff --git a/src/test/auxiliary/struct_variant_xc_aux.rs b/src/test/auxiliary/struct_variant_xc_aux.rs index 8670cd96fc6de..201f028b6b658 100644 --- a/src/test/auxiliary/struct_variant_xc_aux.rs +++ b/src/test/auxiliary/struct_variant_xc_aux.rs @@ -11,7 +11,7 @@ #![crate_name="struct_variant_xc_aux"] #![crate_type = "lib"] -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Enum { Variant(u8), StructVariant { arg: u8 } diff --git a/src/test/auxiliary/xcrate_unit_struct.rs b/src/test/auxiliary/xcrate_unit_struct.rs index 6799cbc6f3355..7a69be2b06c7c 100644 --- a/src/test/auxiliary/xcrate_unit_struct.rs +++ b/src/test/auxiliary/xcrate_unit_struct.rs @@ -12,26 +12,26 @@ // used by the rpass test -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Struct; -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Unit { UnitVariant, Argument(Struct) } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct TupleStruct(pub usize, pub &'static str); // used by the cfail test -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct StructWithFields { foo: isize, } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum EnumWithVariants { EnumVariant, EnumVariantArg(isize) diff --git a/src/test/bench/noise.rs b/src/test/bench/noise.rs index d6577036b8ebe..83c39b3f3faf6 100644 --- a/src/test/bench/noise.rs +++ b/src/test/bench/noise.rs @@ -18,7 +18,7 @@ use std::f32::consts::PI; use std::num::Float; use std::rand::{Rng, StdRng}; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Vec2 { x: f32, y: f32, diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 891d8143dd8c0..72f3464cdb72d 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -54,7 +54,7 @@ fn print_complements() { } } -#[derive(Copy)] +#[derive(Copy, Clone)] enum Color { Red, Yellow, @@ -72,7 +72,7 @@ impl fmt::Debug for Color { } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct CreatureInfo { name: usize, color: Color diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index af9ef80e609ba..4489a124abe0f 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -63,12 +63,12 @@ fn next_permutation(perm: &mut [i32], count: &mut [i32]) { } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct P { p: [i32; 16], } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Perm { cnt: [i32; 16], fact: [u32; 16], diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 7c4cc0eaab7ce..effdd67027a44 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -105,7 +105,7 @@ fn sum_and_scale(a: &'static [AminoAcid]) -> Vec { result } -#[derive(Copy)] +#[derive(Copy, Clone)] struct AminoAcid { c: u8, p: f32, diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index ba4f2c9b1c563..db131bcfdc354 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -64,7 +64,7 @@ static OCCURRENCES: [&'static str;5] = [ // Code implementation -#[derive(Copy, PartialEq, PartialOrd, Ord, Eq)] +#[derive(Copy, Clone, PartialEq, PartialOrd, Ord, Eq)] struct Code(u64); impl Code { diff --git a/src/test/bench/shootout-nbody.rs b/src/test/bench/shootout-nbody.rs index 13154e025d2cd..669a0e86f1e65 100644 --- a/src/test/bench/shootout-nbody.rs +++ b/src/test/bench/shootout-nbody.rs @@ -96,7 +96,7 @@ static BODIES: [Planet;N_BODIES] = [ }, ]; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Planet { x: f64, y: f64, z: f64, vx: f64, vy: f64, vz: f64, diff --git a/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs b/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs index 99618c6bf5626..e5091a92581b4 100644 --- a/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs +++ b/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs @@ -9,13 +9,13 @@ // except according to those terms. -#[derive(Copy)] +#[derive(Copy, Clone)] struct Foo { bar1: Bar, bar2: Bar } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Bar { int1: isize, int2: isize, diff --git a/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs b/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs index 849c98e122e52..440be93dfdca1 100644 --- a/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs +++ b/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs @@ -8,13 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(Copy)] +#[derive(Copy, Clone)] struct Foo { bar1: Bar, bar2: Bar } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Bar { int1: isize, int2: isize, diff --git a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs index b1eb06d16b19a..cce55b6c941b9 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs @@ -10,7 +10,7 @@ use std::ops::Add; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Point { x: isize, y: isize, diff --git a/src/test/compile-fail/borrowck-use-mut-borrow.rs b/src/test/compile-fail/borrowck-use-mut-borrow.rs index e14df7329eac4..c11e58651aa76 100644 --- a/src/test/compile-fail/borrowck-use-mut-borrow.rs +++ b/src/test/compile-fail/borrowck-use-mut-borrow.rs @@ -10,7 +10,7 @@ #![feature(box_syntax)] -#[derive(Copy)] +#[derive(Copy, Clone)] struct A { a: isize, b: isize } struct B { a: isize, b: Box } diff --git a/src/test/run-pass/coherence-cow-1.rs b/src/test/compile-fail/coherence-cow-1.rs similarity index 71% rename from src/test/run-pass/coherence-cow-1.rs rename to src/test/compile-fail/coherence-cow-1.rs index 31f6c9af02024..530bbf57d9104 100644 --- a/src/test/run-pass/coherence-cow-1.rs +++ b/src/test/compile-fail/coherence-cow-1.rs @@ -10,16 +10,19 @@ // aux-build:coherence_lib.rs -// Test that it's ok for T to appear first in the self-type, as long -// as it's covered somewhere. - // pretty-expanded FIXME #23616 +// Test that the `Pair` type reports an error if it contains type +// parameters, even when they are covered by local types. This test +// was originally intended to test the opposite, but the rules changed +// with RFC 1023 and this became illegal. + extern crate coherence_lib as lib; use lib::{Remote,Pair}; pub struct Cover(T); impl Remote for Pair> { } +//~^ ERROR E0210 fn main() { } diff --git a/src/test/run-pass/coherence-cow-2.rs b/src/test/compile-fail/coherence-cow-2.rs similarity index 67% rename from src/test/run-pass/coherence-cow-2.rs rename to src/test/compile-fail/coherence-cow-2.rs index ccda8440ea228..52abceab98b69 100644 --- a/src/test/run-pass/coherence-cow-2.rs +++ b/src/test/compile-fail/coherence-cow-2.rs @@ -10,8 +10,10 @@ // aux-build:coherence_lib.rs -// Test that it's ok for T to appear second in the self-type, as long -// as it's covered somewhere. +// Test that the `Pair` type reports an error if it contains type +// parameters, even when they are covered by local types. This test +// was originally intended to test the opposite, but the rules changed +// with RFC 1023 and this became illegal. // pretty-expanded FIXME #23616 @@ -20,6 +22,6 @@ use lib::{Remote,Pair}; pub struct Cover(T); -impl Remote for Pair,T> { } +impl Remote for Pair,T> { } //~ ERROR E0210 fn main() { } diff --git a/src/test/compile-fail/coherence-cow-no-cover.rs b/src/test/compile-fail/coherence-cow-no-cover.rs index 475d7df1fdb4f..cd32e797ae9bf 100644 --- a/src/test/compile-fail/coherence-cow-no-cover.rs +++ b/src/test/compile-fail/coherence-cow-no-cover.rs @@ -10,7 +10,7 @@ // aux-build:coherence_lib.rs -// Test that it's not ok for U to appear uncovered +// Test that it's not ok for T to appear uncovered extern crate coherence_lib as lib; use lib::{Remote,Pair}; @@ -18,6 +18,6 @@ use lib::{Remote,Pair}; pub struct Cover(T); impl Remote for Pair,U> { } -//~^ ERROR type parameter `U` must be used as the type parameter for some local type +//~^ ERROR type parameter `T` must be used as the type parameter for some local type fn main() { } diff --git a/src/test/compile-fail/coherence-impls-copy.rs b/src/test/compile-fail/coherence-impls-copy.rs index 3034be177ca68..1be606c3546fd 100644 --- a/src/test/compile-fail/coherence-impls-copy.rs +++ b/src/test/compile-fail/coherence-impls-copy.rs @@ -22,18 +22,32 @@ struct NotSync; impl !Sync for NotSync {} impl Copy for TestE {} +impl Clone for TestE { fn clone(&self) -> Self { *self } } + impl Copy for MyType {} + +impl Copy for &'static mut MyType {} +//~^ ERROR E0206 +//~| ERROR E0277 +//~| ERROR E0277 +impl Clone for MyType { fn clone(&self) -> Self { *self } } + impl Copy for (MyType, MyType) {} //~^ ERROR E0206 +//~| ERROR E0117 impl Copy for &'static NotSync {} //~^ ERROR E0206 impl Copy for [MyType] {} //~^ ERROR E0206 +//~| ERROR E0117 +//~| ERROR E0277 +//~| ERROR E0277 impl Copy for &'static [NotSync] {} //~^ ERROR E0206 +//~| ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence-impls-send.rs b/src/test/compile-fail/coherence-impls-send.rs index b05c1ff0f0b72..f130a9353516f 100644 --- a/src/test/compile-fail/coherence-impls-send.rs +++ b/src/test/compile-fail/coherence-impls-send.rs @@ -24,17 +24,17 @@ impl !Sync for NotSync {} unsafe impl Send for TestE {} unsafe impl Send for MyType {} unsafe impl Send for (MyType, MyType) {} -//~^ ERROR E0321 +//~^ ERROR E0117 unsafe impl Send for &'static NotSync {} //~^ ERROR E0321 unsafe impl Send for [MyType] {} -//~^ ERROR E0321 +//~^ ERROR E0117 unsafe impl Send for &'static [NotSync] {} -//~^ ERROR E0321 -//~| ERROR conflicting implementations +//~^ ERROR E0117 +//~| ERROR E0119 fn main() { } diff --git a/src/test/compile-fail/coherence-impls-sized.rs b/src/test/compile-fail/coherence-impls-sized.rs index a9a3ebaffb75a..2ac4bb0492b1f 100644 --- a/src/test/compile-fail/coherence-impls-sized.rs +++ b/src/test/compile-fail/coherence-impls-sized.rs @@ -22,12 +22,17 @@ struct NotSync; impl !Sync for NotSync {} impl Sized for TestE {} //~ ERROR E0322 + impl Sized for MyType {} //~ ERROR E0322 -impl Sized for (MyType, MyType) {} //~ ERROR E0322 + +impl Sized for (MyType, MyType) {} //~ ERROR E0117 + impl Sized for &'static NotSync {} //~ ERROR E0322 -impl Sized for [MyType] {} //~ ERROR E0322 + +impl Sized for [MyType] {} //~ ERROR E0117 //~^ ERROR E0277 -impl Sized for &'static [NotSync] {} //~ ERROR E0322 + +impl Sized for &'static [NotSync] {} //~ ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence-overlap-issue-23516.rs b/src/test/compile-fail/coherence-overlap-issue-23516.rs new file mode 100644 index 0000000000000..d7f060a3bfe73 --- /dev/null +++ b/src/test/compile-fail/coherence-overlap-issue-23516.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tests that we consider `Box: !Sugar` to be ambiguous, even +// though we see no impl of `Sugar` for `Box`. Therefore, an overlap +// error is reported for the following pair of impls (#23516). + +pub trait Sugar { fn dummy(&self) { } } +pub trait Sweet { fn dummy(&self) { } } +impl Sweet for T { } //~ ERROR E0119 +impl Sweet for Box { } +fn main() { } diff --git a/src/test/run-pass/coherence-local-2.rs b/src/test/compile-fail/coherence-vec-local-2.rs similarity index 77% rename from src/test/run-pass/coherence-local-2.rs rename to src/test/compile-fail/coherence-vec-local-2.rs index 5fd3e8ca86ef7..5f0b56af2c226 100644 --- a/src/test/run-pass/coherence-local-2.rs +++ b/src/test/compile-fail/coherence-vec-local-2.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that a local, generic type appearing within a +// *non-fundamental* remote type like `Vec` is not considered local. + // aux-build:coherence_lib.rs // pretty-expanded FIXME #23616 @@ -17,6 +20,6 @@ use lib::Remote; struct Local(T); -impl Remote for Vec> { } +impl Remote for Vec> { } //~ ERROR E0210 fn main() { } diff --git a/src/test/run-pass/coherence-local-1.rs b/src/test/compile-fail/coherence-vec-local.rs similarity index 76% rename from src/test/run-pass/coherence-local-1.rs rename to src/test/compile-fail/coherence-vec-local.rs index 21faa30245d9a..c354caac2b5c2 100644 --- a/src/test/run-pass/coherence-local-1.rs +++ b/src/test/compile-fail/coherence-vec-local.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that a local type (with no type parameters) appearing within a +// *non-fundamental* remote type like `Vec` is not considered local. + // aux-build:coherence_lib.rs // pretty-expanded FIXME #23616 @@ -17,6 +20,6 @@ use lib::Remote; struct Local; -impl Remote for Vec { } +impl Remote for Vec { } //~ ERROR E0117 fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs new file mode 100644 index 0000000000000..f13175ce8e2a4 --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } + +// `MyFundamentalStruct` is declared fundamental, so we can test that +// +// MyFundamentalStruct: !MyTrait +// +// Huzzah. +impl MyTrait for lib::MyFundamentalStruct { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs new file mode 100644 index 0000000000000..ae3d242af705e --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_ref.rs @@ -0,0 +1,36 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } + +// `MyFundamentalStruct` is declared fundamental, so we can test that +// +// MyFundamentalStruct<&MyTrait>: !MyTrait +// +// Huzzah. +impl<'a> MyTrait for lib::MyFundamentalStruct<&'a MyType> { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs new file mode 100644 index 0000000000000..c4e95e772356a --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_fundamental_struct_tuple.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } + +impl MyTrait for T { } //~ ERROR E0119 + +// Tuples are not fundamental. +impl MyTrait for lib::MyFundamentalStruct<(MyType,)> { } + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_struct.rs b/src/test/compile-fail/coherence_copy_like_err_struct.rs new file mode 100644 index 0000000000000..f768a475ee820 --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_struct.rs @@ -0,0 +1,33 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:coherence_copy_like_lib.rs + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } //~ ERROR E0119 + +// `MyStruct` is not declared fundamental, therefore this would +// require that +// +// MyStruct: !MyTrait +// +// which we cannot approve. +impl MyTrait for lib::MyStruct { } + +fn main() { } diff --git a/src/test/compile-fail/coherence_copy_like_err_tuple.rs b/src/test/compile-fail/coherence_copy_like_err_tuple.rs new file mode 100644 index 0000000000000..0c78fffd2dfab --- /dev/null +++ b/src/test/compile-fail/coherence_copy_like_err_tuple.rs @@ -0,0 +1,32 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } //~ ERROR E0119 + +// Tuples are not fundamental, therefore this would require that +// +// (MyType,): !MyTrait +// +// which we cannot approve. +impl MyTrait for (MyType,) { } + +fn main() { } diff --git a/src/test/compile-fail/coherence_local.rs b/src/test/compile-fail/coherence_local.rs new file mode 100644 index 0000000000000..551577b6b4e08 --- /dev/null +++ b/src/test/compile-fail/coherence_local.rs @@ -0,0 +1,33 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +impl lib::MyCopy for MyType { } +impl<'a> lib::MyCopy for &'a MyType { } +impl<'a> lib::MyCopy for &'a Box { } +impl lib::MyCopy for Box { } +impl lib::MyCopy for lib::MyFundamentalStruct { } +impl lib::MyCopy for lib::MyFundamentalStruct> { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/coherence_local_err_struct.rs b/src/test/compile-fail/coherence_local_err_struct.rs new file mode 100644 index 0000000000000..01f4c1cd8a5c9 --- /dev/null +++ b/src/test/compile-fail/coherence_local_err_struct.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +// MyStruct is not fundamental. +impl lib::MyCopy for lib::MyStruct { } //~ ERROR E0117 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_local_err_tuple.rs b/src/test/compile-fail/coherence_local_err_tuple.rs new file mode 100644 index 0000000000000..590f68cee59ef --- /dev/null +++ b/src/test/compile-fail/coherence_local_err_tuple.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// These are all legal because they are all fundamental types: + +// Tuples are not fundamental, so this is not a local impl. +impl lib::MyCopy for (MyType,) { } //~ ERROR E0117 + +#[rustc_error] +fn main() { } diff --git a/src/test/compile-fail/coherence_local_ref.rs b/src/test/compile-fail/coherence_local_ref.rs new file mode 100644 index 0000000000000..f6e1aab59766a --- /dev/null +++ b/src/test/compile-fail/coherence_local_ref.rs @@ -0,0 +1,27 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +#![feature(rustc_attrs)] +#![allow(dead_code)] + +extern crate coherence_copy_like_lib as lib; + +struct MyType { x: i32 } + +// naturally, legal +impl lib::MyCopy for MyType { } + +#[rustc_error] +fn main() { } //~ ERROR compilation successful diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs index ddc929017718d..2d87345db2245 100644 --- a/src/test/compile-fail/dst-bad-coerce1.rs +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -23,10 +23,6 @@ pub fn main() { let f2: &Fat<[isize; 3]> = &f1; let f3: &Fat<[usize]> = f2; //~^ ERROR mismatched types - //~| expected `&Fat<[usize]>` - //~| found `&Fat<[isize; 3]>` - //~| expected usize - //~| found isize // With a trait. let f1 = Fat { ptr: Foo }; diff --git a/src/test/compile-fail/dst-index.rs b/src/test/compile-fail/dst-index.rs index 021ef7343cbb4..c52458934bd1c 100644 --- a/src/test/compile-fail/dst-index.rs +++ b/src/test/compile-fail/dst-index.rs @@ -14,7 +14,7 @@ use std::ops::Index; use std::fmt::Debug; -#[derive(Copy)] +#[derive(Copy, Clone)] struct S; impl Index for S { @@ -25,7 +25,7 @@ impl Index for S { } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct T; impl Index for T { diff --git a/src/test/compile-fail/exclusive-drop-and-copy.rs b/src/test/compile-fail/exclusive-drop-and-copy.rs index f47f14d587992..460c396750ff0 100644 --- a/src/test/compile-fail/exclusive-drop-and-copy.rs +++ b/src/test/compile-fail/exclusive-drop-and-copy.rs @@ -12,14 +12,14 @@ // issue #20126 -#[derive(Copy)] //~ ERROR the trait `Copy` may not be implemented +#[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented struct Foo; impl Drop for Foo { fn drop(&mut self) {} } -#[derive(Copy)] //~ ERROR the trait `Copy` may not be implemented +#[derive(Copy, Clone)] //~ ERROR the trait `Copy` may not be implemented struct Bar(::std::marker::PhantomData); #[unsafe_destructor] diff --git a/src/test/compile-fail/feature-gate-rust-call.rs b/src/test/compile-fail/feature-gate-rust-call.rs new file mode 100644 index 0000000000000..029a9cad65fcf --- /dev/null +++ b/src/test/compile-fail/feature-gate-rust-call.rs @@ -0,0 +1,21 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change + +trait Foo { + extern "rust-call" fn foo(); +} + +impl Foo for i32 { + extern "rust-call" fn foo() { } //~ ERROR rust-call ABI is subject to change +} + +fn main() { } diff --git a/src/test/compile-fail/feature-gate-simd-ffi.rs b/src/test/compile-fail/feature-gate-simd-ffi.rs index 9ee3fcee02355..dcd7a0ded812f 100644 --- a/src/test/compile-fail/feature-gate-simd-ffi.rs +++ b/src/test/compile-fail/feature-gate-simd-ffi.rs @@ -13,7 +13,7 @@ use std::simd::f32x4; -#[simd] #[derive(Copy)] #[repr(C)] struct LocalSimd(u8, u8); +#[simd] #[derive(Copy, Clone)] #[repr(C)] struct LocalSimd(u8, u8); extern { fn foo() -> f32x4; //~ ERROR use of SIMD type diff --git a/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs index d86c5d211dc5f..5df309321d310 100644 --- a/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs +++ b/src/test/compile-fail/feature-gate-unboxed-closures-manual-impls.rs @@ -17,23 +17,23 @@ struct Foo; impl Fn<()> for Foo { - //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits extern "rust-call" fn call(self, args: ()) -> () {} + //~^ ERROR rust-call ABI is subject to change } struct Foo1; impl FnOnce() for Foo1 { - //~^ ERROR associated type bindings are not allowed here extern "rust-call" fn call_once(self, args: ()) -> () {} + //~^ ERROR rust-call ABI is subject to change } struct Bar; impl FnMut<()> for Bar { - //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits extern "rust-call" fn call_mut(&self, args: ()) -> () {} + //~^ ERROR rust-call ABI is subject to change } struct Baz; impl FnOnce<()> for Baz { - //~^ ERROR angle-bracket notation is not stable when used with the `Fn` family of traits extern "rust-call" fn call_once(&self, args: ()) -> () {} + //~^ ERROR rust-call ABI is subject to change } fn main() {} diff --git a/src/test/compile-fail/gated-simd-ffi.rs b/src/test/compile-fail/gated-simd-ffi.rs index c0a251e77a316..883e1be04b228 100644 --- a/src/test/compile-fail/gated-simd-ffi.rs +++ b/src/test/compile-fail/gated-simd-ffi.rs @@ -13,7 +13,7 @@ #![feature(simd)] #[repr(C)] -#[derive(Copy)] +#[derive(Copy, Clone)] #[simd] pub struct f32x4(f32, f32, f32, f32); diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs index d5bfe3d16925c..1925caf6870ee 100644 --- a/src/test/compile-fail/kindck-copy.rs +++ b/src/test/compile-fail/kindck-copy.rs @@ -17,7 +17,7 @@ fn assert_copy() { } trait Dummy : MarkerTrait { } -#[derive(Copy)] +#[derive(Copy, Clone)] struct MyStruct { x: isize, y: isize, diff --git a/src/test/compile-fail/kindck-inherited-copy-bound.rs b/src/test/compile-fail/kindck-inherited-copy-bound.rs index 52ca24d0f547a..066590252a54a 100644 --- a/src/test/compile-fail/kindck-inherited-copy-bound.rs +++ b/src/test/compile-fail/kindck-inherited-copy-bound.rs @@ -25,13 +25,13 @@ fn take_param(foo: &T) { } fn a() { let x: Box<_> = box 3; - take_param(&x); //~ ERROR `core::marker::Copy` is not implemented + take_param(&x); //~ ERROR E0277 } fn b() { let x: Box<_> = box 3; let y = &x; - let z = &x as &Foo; //~ ERROR `core::marker::Copy` is not implemented + let z = &x as &Foo; //~ ERROR E0038 } fn main() { } diff --git a/src/test/compile-fail/object-lifetime-default-elision.rs b/src/test/compile-fail/object-lifetime-default-elision.rs index 0077d10e6ca82..4fba45e2a66c5 100644 --- a/src/test/compile-fail/object-lifetime-default-elision.rs +++ b/src/test/compile-fail/object-lifetime-default-elision.rs @@ -81,8 +81,8 @@ fn load3<'a,'b>(ss: &'a SomeTrait) -> &'b SomeTrait { // which fails to type check. ss - //~^ ERROR cannot infer - //~| ERROR mismatched types + //~^ ERROR lifetime of the source pointer does not outlive lifetime bound + //~| ERROR cannot infer } fn main() { diff --git a/src/test/compile-fail/object-lifetime-default-from-box-error.rs b/src/test/compile-fail/object-lifetime-default-from-box-error.rs index 70752cbfda19f..7fae530984f89 100644 --- a/src/test/compile-fail/object-lifetime-default-from-box-error.rs +++ b/src/test/compile-fail/object-lifetime-default-from-box-error.rs @@ -25,7 +25,7 @@ fn load(ss: &mut SomeStruct) -> Box { // `Box` defaults to a `'static` bound, so this return // is illegal. - ss.r //~ ERROR mismatched types + ss.r //~ ERROR lifetime of the source pointer does not outlive lifetime bound } fn store(ss: &mut SomeStruct, b: Box) { @@ -38,7 +38,7 @@ fn store(ss: &mut SomeStruct, b: Box) { fn store1<'b>(ss: &mut SomeStruct, b: Box) { // Here we override the lifetimes explicitly, and so naturally we get an error. - ss.r = b; //~ ERROR mismatched types + ss.r = b; //~ ERROR lifetime of the source pointer does not outlive lifetime bound } fn main() { diff --git a/src/test/compile-fail/opt-in-copy.rs b/src/test/compile-fail/opt-in-copy.rs index bc18b52a0c1c9..be321b6290354 100644 --- a/src/test/compile-fail/opt-in-copy.rs +++ b/src/test/compile-fail/opt-in-copy.rs @@ -16,6 +16,7 @@ struct IWantToCopyThis { impl Copy for IWantToCopyThis {} //~^ ERROR the trait `Copy` may not be implemented for this type +//~| ERROR E0277 enum CantCopyThisEither { A, @@ -28,5 +29,6 @@ enum IWantToCopyThisToo { impl Copy for IWantToCopyThisToo {} //~^ ERROR the trait `Copy` may not be implemented for this type +//~| ERROR E0277 fn main() {} diff --git a/src/test/compile-fail/pub-method-macro.rs b/src/test/compile-fail/pub-method-macro.rs index aa890550f1c48..198fa5b9aca0b 100644 --- a/src/test/compile-fail/pub-method-macro.rs +++ b/src/test/compile-fail/pub-method-macro.rs @@ -20,7 +20,7 @@ mod bleh { ) } - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct S; impl S { diff --git a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs index 0f8bc6d684f12..10b883d4dc830 100644 --- a/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs +++ b/src/test/compile-fail/regions-close-over-type-parameter-multiple.rs @@ -27,7 +27,7 @@ fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box { fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box { // A outlives 'a AND 'b...but not 'c. - box v as Box //~ ERROR mismatched types + box v as Box //~ ERROR lifetime of the source pointer does not outlive } fn main() { diff --git a/src/test/compile-fail/regions-trait-object-subtyping.rs b/src/test/compile-fail/regions-trait-object-subtyping.rs index 8d05cb67e77b1..f3722690ef895 100644 --- a/src/test/compile-fail/regions-trait-object-subtyping.rs +++ b/src/test/compile-fail/regions-trait-object-subtyping.rs @@ -22,7 +22,7 @@ fn foo2<'a:'b,'b>(x: &'b mut (Dummy+'a)) -> &'b mut (Dummy+'b) { fn foo3<'a,'b>(x: &'a mut Dummy) -> &'b mut Dummy { // Without knowing 'a:'b, we can't coerce - x //~ ERROR mismatched types + x //~ ERROR lifetime of the source pointer does not outlive //~^ ERROR cannot infer } diff --git a/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs index 7d25c04882f24..b1febae768036 100644 --- a/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs +++ b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs @@ -20,15 +20,15 @@ extern crate typeck_default_trait_impl_cross_crate_coherence_lib as lib; use lib::DefaultedTrait; struct A; -impl DefaultedTrait for (A,) { } //~ ERROR E0321 +impl DefaultedTrait for (A,) { } //~ ERROR E0117 struct B; -impl !DefaultedTrait for (B,) { } //~ ERROR E0321 +impl !DefaultedTrait for (B,) { } //~ ERROR E0117 struct C; struct D(T); impl DefaultedTrait for Box { } //~ ERROR E0321 -impl DefaultedTrait for lib::Something { } //~ ERROR E0321 +impl DefaultedTrait for lib::Something { } //~ ERROR E0117 impl DefaultedTrait for D { } // OK fn main() { } diff --git a/src/test/compile-fail/unsendable-class.rs b/src/test/compile-fail/unsendable-class.rs deleted file mode 100644 index f51eee379347c..0000000000000 --- a/src/test/compile-fail/unsendable-class.rs +++ /dev/null @@ -1,35 +0,0 @@ -// 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::sync::mpsc::channel; - -// Test that a class with an unsendable field can't be -// sent - -use std::rc::Rc; - -struct foo { - i: isize, - j: Rc, -} - -fn foo(i:isize, j: Rc) -> foo { - foo { - i: i, - j: j - } -} - -fn main() { - let cat = "kitty".to_string(); - let (tx, _) = channel(); - //~^ ERROR `core::marker::Send` is not implemented - tx.send(foo(42, Rc::new(cat))); -} diff --git a/src/test/debuginfo/c-style-enum.rs b/src/test/debuginfo/c-style-enum.rs index 7a285d90b9d6a..3024ca0fe6983 100644 --- a/src/test/debuginfo/c-style-enum.rs +++ b/src/test/debuginfo/c-style-enum.rs @@ -105,21 +105,21 @@ use self::AutoDiscriminant::{One, Two, Three}; use self::ManualDiscriminant::{OneHundred, OneThousand, OneMillion}; use self::SingleVariant::TheOnlyVariant; -#[derive(Copy)] +#[derive(Copy, Clone)] enum AutoDiscriminant { One, Two, Three } -#[derive(Copy)] +#[derive(Copy, Clone)] enum ManualDiscriminant { OneHundred = 100, OneThousand = 1000, OneMillion = 1000000 } -#[derive(Copy)] +#[derive(Copy, Clone)] enum SingleVariant { TheOnlyVariant } diff --git a/src/test/debuginfo/generic-method-on-generic-struct.rs b/src/test/debuginfo/generic-method-on-generic-struct.rs index 06053965ca757..fc9ef8e3a98ed 100644 --- a/src/test/debuginfo/generic-method-on-generic-struct.rs +++ b/src/test/debuginfo/generic-method-on-generic-struct.rs @@ -114,7 +114,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: T } diff --git a/src/test/debuginfo/method-on-enum.rs b/src/test/debuginfo/method-on-enum.rs index 314ec472b6941..6468a36f8c61c 100644 --- a/src/test/debuginfo/method-on-enum.rs +++ b/src/test/debuginfo/method-on-enum.rs @@ -115,7 +115,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] enum Enum { Variant1 { x: u16, y: u16 }, Variant2 (u32) diff --git a/src/test/debuginfo/method-on-generic-struct.rs b/src/test/debuginfo/method-on-generic-struct.rs index 564c2d26493d2..975668baa1285 100644 --- a/src/test/debuginfo/method-on-generic-struct.rs +++ b/src/test/debuginfo/method-on-generic-struct.rs @@ -115,7 +115,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: T } diff --git a/src/test/debuginfo/method-on-struct.rs b/src/test/debuginfo/method-on-struct.rs index eba4370e698ed..28885d0ad9b79 100644 --- a/src/test/debuginfo/method-on-struct.rs +++ b/src/test/debuginfo/method-on-struct.rs @@ -115,7 +115,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: isize } diff --git a/src/test/debuginfo/method-on-trait.rs b/src/test/debuginfo/method-on-trait.rs index 6df7cdfd47f18..b69a3856736c4 100644 --- a/src/test/debuginfo/method-on-trait.rs +++ b/src/test/debuginfo/method-on-trait.rs @@ -115,7 +115,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: isize } diff --git a/src/test/debuginfo/method-on-tuple-struct.rs b/src/test/debuginfo/method-on-tuple-struct.rs index b638e210dd38a..97d4496cce12b 100644 --- a/src/test/debuginfo/method-on-tuple-struct.rs +++ b/src/test/debuginfo/method-on-tuple-struct.rs @@ -115,7 +115,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] struct TupleStruct(isize, f64); impl TupleStruct { diff --git a/src/test/debuginfo/self-in-default-method.rs b/src/test/debuginfo/self-in-default-method.rs index f61b78d5449e7..f16f236a0cb06 100644 --- a/src/test/debuginfo/self-in-default-method.rs +++ b/src/test/debuginfo/self-in-default-method.rs @@ -114,7 +114,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: isize } diff --git a/src/test/debuginfo/self-in-generic-default-method.rs b/src/test/debuginfo/self-in-generic-default-method.rs index 4ac436c9325bb..56de877016dee 100644 --- a/src/test/debuginfo/self-in-generic-default-method.rs +++ b/src/test/debuginfo/self-in-generic-default-method.rs @@ -114,7 +114,7 @@ #![feature(box_syntax)] #![omit_gdb_pretty_printer_section] -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: isize } diff --git a/src/test/debuginfo/unreachable-locals.rs b/src/test/debuginfo/unreachable-locals.rs index 309848d6cedc9..63536b1383475 100644 --- a/src/test/debuginfo/unreachable-locals.rs +++ b/src/test/debuginfo/unreachable-locals.rs @@ -26,6 +26,22 @@ fn after_return() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } fn after_panic() { @@ -36,6 +52,22 @@ fn after_panic() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } fn after_diverging_function() { @@ -46,6 +78,22 @@ fn after_diverging_function() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } fn after_break() { @@ -57,18 +105,50 @@ fn after_break() { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } } fn after_continue() { for _ in 0..10i32 { - break; + continue; let x = "0"; let (ref y,z) = (1i32, 2u32); match (20i32, 'c') { (a, ref b) => {} } for a in &[111i32] {} + let test = if some_predicate() { 1 } else { 2 }; + while some_predicate() { + let abc = !some_predicate(); + } + loop { + let abc = !some_predicate(); + break; + } + // nested block + { + let abc = !some_predicate(); + + { + let def = !some_predicate(); + } + } } } @@ -83,3 +163,6 @@ fn main() { fn diverge() -> ! { panic!(); } + +fn some_predicate() -> bool { true || false } + diff --git a/src/test/pretty/block-disambig.rs b/src/test/pretty/block-disambig.rs index 6e75e08513848..3d5e6e78deaf1 100644 --- a/src/test/pretty/block-disambig.rs +++ b/src/test/pretty/block-disambig.rs @@ -19,7 +19,7 @@ fn test1() { let val = &0; { } *val; } fn test2() -> isize { let val = &0; { } *val } -#[derive(Copy)] +#[derive(Copy, Clone)] struct S { eax: isize } fn test3() { diff --git a/src/test/run-make/allow-non-lint-warnings-cmdline/foo.rs b/src/test/run-make/allow-non-lint-warnings-cmdline/foo.rs index 19ce5d0a7ca40..a9e18f5a8f1e6 100644 --- a/src/test/run-make/allow-non-lint-warnings-cmdline/foo.rs +++ b/src/test/run-make/allow-non-lint-warnings-cmdline/foo.rs @@ -9,7 +9,7 @@ // except according to those terms. #[derive()] -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Foo; pub fn main() { } diff --git a/src/test/run-make/extern-fn-with-packed-struct/test.rs b/src/test/run-make/extern-fn-with-packed-struct/test.rs index 838ef338846a8..c0f55893a3abe 100644 --- a/src/test/run-make/extern-fn-with-packed-struct/test.rs +++ b/src/test/run-make/extern-fn-with-packed-struct/test.rs @@ -9,7 +9,7 @@ // except according to those terms. #[repr(packed)] -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] struct Foo { a: i8, b: i16, diff --git a/src/test/run-make/rustdoc-extern-method/bar.rs b/src/test/run-make/rustdoc-extern-method/bar.rs index 672090c13a233..26a05f8490fd1 100644 --- a/src/test/run-make/rustdoc-extern-method/bar.rs +++ b/src/test/run-make/rustdoc-extern-method/bar.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(unboxed_closures)] + extern crate foo; // @has bar/trait.Foo.html //pre "pub trait Foo" diff --git a/src/test/run-make/rustdoc-extern-method/foo.rs b/src/test/run-make/rustdoc-extern-method/foo.rs index fc5f03e8bd36a..96a7a8378b792 100644 --- a/src/test/run-make/rustdoc-extern-method/foo.rs +++ b/src/test/run-make/rustdoc-extern-method/foo.rs @@ -9,6 +9,7 @@ // except according to those terms. #![crate_type="lib"] +#![feature(unboxed_closures)] pub trait Foo { extern "rust-call" fn foo(&self, _: ()) -> i32; diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs index 5310ed25d3b1b..9d1ab00359dd9 100644 --- a/src/test/run-make/save-analysis/foo.rs +++ b/src/test/run-make/save-analysis/foo.rs @@ -179,7 +179,7 @@ enum SomeEnum<'a> { MyTypes(MyType, MyType) } -#[derive(Copy)] +#[derive(Copy, Clone)] enum SomeOtherEnum { SomeConst1, SomeConst2, diff --git a/src/test/run-pass/associated-types-normalize-unifield-struct.rs b/src/test/run-pass/associated-types-normalize-unifield-struct.rs index 82adac8cf8614..3dffae99292c6 100644 --- a/src/test/run-pass/associated-types-normalize-unifield-struct.rs +++ b/src/test/run-pass/associated-types-normalize-unifield-struct.rs @@ -20,10 +20,10 @@ pub trait Offset { fn dummy(&self) { } } -#[derive(Copy)] pub struct X; +#[derive(Copy, Clone)] pub struct X; impl Offset for X { type State = Y; } -#[derive(Copy)] pub struct Y; +#[derive(Copy, Clone)] pub struct Y; impl OffsetState for Y {} pub fn now() -> DateTime { from_utc(Y) } diff --git a/src/test/run-pass/binops-issue-22743.rs b/src/test/run-pass/binops-issue-22743.rs index 01c85023eda39..da7a3ae684c57 100644 --- a/src/test/run-pass/binops-issue-22743.rs +++ b/src/test/run-pass/binops-issue-22743.rs @@ -10,7 +10,7 @@ use std::ops::Mul; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Foo { x: f64, } diff --git a/src/test/run-pass/borrowck-univariant-enum.rs b/src/test/run-pass/borrowck-univariant-enum.rs index 84efe1903671f..a5c68c5ecf976 100644 --- a/src/test/run-pass/borrowck-univariant-enum.rs +++ b/src/test/run-pass/borrowck-univariant-enum.rs @@ -13,7 +13,7 @@ use std::cell::Cell; -#[derive(Copy)] +#[derive(Copy, Clone)] enum newtype { newvar(isize) } diff --git a/src/test/run-pass/builtin-superkinds-in-metadata.rs b/src/test/run-pass/builtin-superkinds-in-metadata.rs index 717348652ed61..c026ffc6d318d 100644 --- a/src/test/run-pass/builtin-superkinds-in-metadata.rs +++ b/src/test/run-pass/builtin-superkinds-in-metadata.rs @@ -20,7 +20,7 @@ use trait_superkinds_in_metadata::{RequiresRequiresShareAndSend, RequiresShare}; use trait_superkinds_in_metadata::RequiresCopy; use std::marker; -#[derive(Copy)] +#[derive(Copy, Clone)] struct X(T); impl RequiresShare for X { } diff --git a/src/test/run-pass/class-impl-very-parameterized-trait.rs b/src/test/run-pass/class-impl-very-parameterized-trait.rs index 57c1fd80bd542..4c494293b517e 100644 --- a/src/test/run-pass/class-impl-very-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-very-parameterized-trait.rs @@ -11,7 +11,7 @@ use std::cmp; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum cat_type { tuxedo, tabby, tortoiseshell } impl cmp::PartialEq for cat_type { diff --git a/src/test/run-pass/coherence-impl-in-fn.rs b/src/test/run-pass/coherence-impl-in-fn.rs index 134549d747a0a..b0630b516407b 100644 --- a/src/test/run-pass/coherence-impl-in-fn.rs +++ b/src/test/run-pass/coherence-impl-in-fn.rs @@ -11,7 +11,7 @@ // pretty-expanded FIXME #23616 pub fn main() { - #[derive(Copy)] + #[derive(Copy, Clone)] enum x { foo } impl ::std::cmp::PartialEq for x { fn eq(&self, other: &x) -> bool { diff --git a/src/test/run-pass/coherence_copy_like.rs b/src/test/run-pass/coherence_copy_like.rs new file mode 100644 index 0000000000000..db9893613ad11 --- /dev/null +++ b/src/test/run-pass/coherence_copy_like.rs @@ -0,0 +1,29 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we are able to introduce a negative constraint that +// `MyType: !MyTrait` along with other "fundamental" wrappers. + +// aux-build:coherence_copy_like_lib.rs + +extern crate coherence_copy_like_lib as lib; + +use std::marker::MarkerTrait; + +struct MyType { x: i32 } + +trait MyTrait : MarkerTrait { } +impl MyTrait for T { } +impl MyTrait for MyType { } +impl<'a> MyTrait for &'a MyType { } +impl MyTrait for Box { } +impl<'a> MyTrait for &'a Box { } + +fn main() { } diff --git a/src/test/run-pass/const-nullary-univariant-enum.rs b/src/test/run-pass/const-nullary-univariant-enum.rs index d0e9e5d610606..51926ececc2b1 100644 --- a/src/test/run-pass/const-nullary-univariant-enum.rs +++ b/src/test/run-pass/const-nullary-univariant-enum.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] enum Foo { Bar = 0xDEADBEE } diff --git a/src/test/run-pass/copy-out-of-array-1.rs b/src/test/run-pass/copy-out-of-array-1.rs index 6dfcc3b2a165a..5c5765454d457 100644 --- a/src/test/run-pass/copy-out-of-array-1.rs +++ b/src/test/run-pass/copy-out-of-array-1.rs @@ -14,10 +14,9 @@ // pretty-expanded FIXME #23616 +#[derive(Copy, Clone)] struct C { _x: u8 } -impl Copy for C { } - fn main() { fn d() -> C { C { _x: 0 } } diff --git a/src/test/run-pass/deriving-bounds.rs b/src/test/run-pass/deriving-bounds.rs index e0bbd0b2b041e..4204d9b5c3eae 100644 --- a/src/test/run-pass/deriving-bounds.rs +++ b/src/test/run-pass/deriving-bounds.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] struct Test; pub fn main() {} diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs index fd19d02e688e9..9bf286c434219 100644 --- a/src/test/run-pass/dst-struct-sole.rs +++ b/src/test/run-pass/dst-struct-sole.rs @@ -32,7 +32,7 @@ fn foo2(x: &Fat<[T]>) { assert!(x.ptr[1].to_bar() == bar); } -#[derive(Copy, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] struct Bar; trait ToBar { diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs index 055b61b25fbf7..5198dd43d6db8 100644 --- a/src/test/run-pass/dst-struct.rs +++ b/src/test/run-pass/dst-struct.rs @@ -51,7 +51,7 @@ fn foo3(x: &Fat>) { } -#[derive(Copy, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] struct Bar; trait ToBar { diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs index ede4b8c442e17..370bc2882271f 100644 --- a/src/test/run-pass/dst-trait.rs +++ b/src/test/run-pass/dst-trait.rs @@ -19,10 +19,10 @@ struct Fat { ptr: T } -#[derive(Copy, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] struct Bar; -#[derive(Copy, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] struct Bar1 { f: isize } diff --git a/src/test/run-pass/empty-tag.rs b/src/test/run-pass/empty-tag.rs index ff2a70467ea88..e60cd02ce9994 100644 --- a/src/test/run-pass/empty-tag.rs +++ b/src/test/run-pass/empty-tag.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum chan { chan_t, } impl PartialEq for chan { diff --git a/src/test/run-pass/enum-discrim-width-stuff.rs b/src/test/run-pass/enum-discrim-width-stuff.rs index 0242e53aa8c4f..46238c4572080 100644 --- a/src/test/run-pass/enum-discrim-width-stuff.rs +++ b/src/test/run-pass/enum-discrim-width-stuff.rs @@ -12,7 +12,7 @@ macro_rules! check { ($m:ident, $t:ty, $v:expr) => {{ mod $m { use std::mem::size_of; - #[derive(Copy, Debug)] + #[derive(Copy, Clone, Debug)] enum E { V = $v, A = 0 diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs index 25f09ee94b019..ee50d3bdf0ee8 100644 --- a/src/test/run-pass/explicit-self-generic.rs +++ b/src/test/run-pass/explicit-self-generic.rs @@ -13,7 +13,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] -#[derive(Copy)] +#[derive(Copy, Clone)] struct LM { resize_at: usize, size: usize } enum HashMap { diff --git a/src/test/run-pass/expr-copy.rs b/src/test/run-pass/expr-copy.rs index 80729fb216474..ca394f991f29b 100644 --- a/src/test/run-pass/expr-copy.rs +++ b/src/test/run-pass/expr-copy.rs @@ -15,7 +15,7 @@ fn f(arg: &mut A) { arg.a = 100; } -#[derive(Copy)] +#[derive(Copy, Clone)] struct A { a: isize } pub fn main() { diff --git a/src/test/run-pass/expr-if-struct.rs b/src/test/run-pass/expr-if-struct.rs index ad39783063854..e79daed4c33d7 100644 --- a/src/test/run-pass/expr-if-struct.rs +++ b/src/test/run-pass/expr-if-struct.rs @@ -14,7 +14,7 @@ // Tests for if as expressions returning nominal types -#[derive(Copy)] +#[derive(Copy, Clone)] struct I { i: isize } fn test_rec() { @@ -22,7 +22,7 @@ fn test_rec() { assert_eq!(rs.i, 100); } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum mood { happy, sad, } impl PartialEq for mood { diff --git a/src/test/run-pass/expr-match-struct.rs b/src/test/run-pass/expr-match-struct.rs index 91ad142c3863a..2dcb0f833e4b3 100644 --- a/src/test/run-pass/expr-match-struct.rs +++ b/src/test/run-pass/expr-match-struct.rs @@ -13,7 +13,7 @@ // Tests for match as expressions resulting in struct types -#[derive(Copy)] +#[derive(Copy, Clone)] struct R { i: isize } fn test_rec() { @@ -21,7 +21,7 @@ fn test_rec() { assert_eq!(rs.i, 100); } -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum mood { happy, sad, } impl PartialEq for mood { diff --git a/src/test/run-pass/exterior.rs b/src/test/run-pass/exterior.rs index 25a990383e412..9a039e8bc3539 100644 --- a/src/test/run-pass/exterior.rs +++ b/src/test/run-pass/exterior.rs @@ -13,7 +13,7 @@ use std::cell::Cell; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Point {x: isize, y: isize, z: isize} fn f(p: &Cell) { diff --git a/src/test/run-pass/extern-pass-TwoU16s.rs b/src/test/run-pass/extern-pass-TwoU16s.rs index 1f48dc3bcf1d7..9d304ea9e10b6 100644 --- a/src/test/run-pass/extern-pass-TwoU16s.rs +++ b/src/test/run-pass/extern-pass-TwoU16s.rs @@ -11,7 +11,7 @@ // Test a foreign function that accepts and returns a struct // by value. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct TwoU16s { one: u16, two: u16 } diff --git a/src/test/run-pass/extern-pass-TwoU32s.rs b/src/test/run-pass/extern-pass-TwoU32s.rs index 171e2a647cc63..8dae0473fd5ed 100644 --- a/src/test/run-pass/extern-pass-TwoU32s.rs +++ b/src/test/run-pass/extern-pass-TwoU32s.rs @@ -11,7 +11,7 @@ // Test a foreign function that accepts and returns a struct // by value. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct TwoU32s { one: u32, two: u32 } diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs index 83555f6bb1d51..14aeea3465798 100644 --- a/src/test/run-pass/extern-pass-TwoU64s.rs +++ b/src/test/run-pass/extern-pass-TwoU64s.rs @@ -11,7 +11,7 @@ // Test a foreign function that accepts and returns a struct // by value. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct TwoU64s { one: u64, two: u64 } diff --git a/src/test/run-pass/extern-pass-TwoU8s.rs b/src/test/run-pass/extern-pass-TwoU8s.rs index d2b13445e6a22..75a109e442911 100644 --- a/src/test/run-pass/extern-pass-TwoU8s.rs +++ b/src/test/run-pass/extern-pass-TwoU8s.rs @@ -11,7 +11,7 @@ // Test a foreign function that accepts and returns a struct // by value. -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] pub struct TwoU8s { one: u8, two: u8 } diff --git a/src/test/run-pass/foreign-fn-with-byval.rs b/src/test/run-pass/foreign-fn-with-byval.rs index 4c0633d49c65f..7883c22f909dd 100644 --- a/src/test/run-pass/foreign-fn-with-byval.rs +++ b/src/test/run-pass/foreign-fn-with-byval.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct S { x: u64, y: u64, diff --git a/src/test/run-pass/generic-fn.rs b/src/test/run-pass/generic-fn.rs index 82b03abf0570b..0ba0ed4bf7f97 100644 --- a/src/test/run-pass/generic-fn.rs +++ b/src/test/run-pass/generic-fn.rs @@ -12,7 +12,7 @@ fn id(x: T) -> T { return x; } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Triple {x: isize, y: isize, z: isize} pub fn main() { diff --git a/src/test/run-pass/guards-not-exhaustive.rs b/src/test/run-pass/guards-not-exhaustive.rs index 59ec14e097e67..f5f80914937d3 100644 --- a/src/test/run-pass/guards-not-exhaustive.rs +++ b/src/test/run-pass/guards-not-exhaustive.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] enum Q { R(Option) } fn xyzzy(q: Q) -> usize { diff --git a/src/test/run-pass/guards.rs b/src/test/run-pass/guards.rs index 598172ac18ead..11c67b8af8107 100644 --- a/src/test/run-pass/guards.rs +++ b/src/test/run-pass/guards.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] struct Pair { x: isize, y: isize } pub fn main() { diff --git a/src/test/run-pass/hrtb-opt-in-copy.rs b/src/test/run-pass/hrtb-opt-in-copy.rs index 8ececb3875acb..b40f4d27a9c4d 100644 --- a/src/test/run-pass/hrtb-opt-in-copy.rs +++ b/src/test/run-pass/hrtb-opt-in-copy.rs @@ -22,7 +22,7 @@ use std::marker::PhantomData; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Foo { x: T } type Ty<'tcx> = &'tcx TyS<'tcx>; @@ -31,7 +31,7 @@ enum TyS<'tcx> { Boop(PhantomData<*mut &'tcx ()>) } -#[derive(Copy)] +#[derive(Copy, Clone)] enum Bar<'tcx> { Baz(Foo>) } diff --git a/src/test/run-pass/issue-11709.rs b/src/test/run-pass/issue-11709.rs index da3efb4fea8ca..3ad78f088f9c9 100644 --- a/src/test/run-pass/issue-11709.rs +++ b/src/test/run-pass/issue-11709.rs @@ -25,7 +25,7 @@ fn test(slot: &mut Option>) -> () { let a = slot.take(); let _a = match a { // `{let .. a(); }` would break - Some(a) => { let _a = a.invoke(()); }, + Some(a) => { let _a = a(); }, None => (), }; } diff --git a/src/test/run-pass/issue-11958.rs b/src/test/run-pass/issue-11958.rs index ed2009dab1baf..def85b4766783 100644 --- a/src/test/run-pass/issue-11958.rs +++ b/src/test/run-pass/issue-11958.rs @@ -23,5 +23,5 @@ use std::thunk::Thunk; pub fn main() { let mut x = 1; - let _thunk = Thunk::new(move|| { x = 2; }); + let _thunk = Box::new(move|| { x = 2; }); } diff --git a/src/test/run-pass/issue-12860.rs b/src/test/run-pass/issue-12860.rs index ad03c7fddb49b..dddfb9bacf9e2 100644 --- a/src/test/run-pass/issue-12860.rs +++ b/src/test/run-pass/issue-12860.rs @@ -16,7 +16,7 @@ extern crate collections; use std::collections::HashSet; -#[derive(Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] struct XYZ { x: isize, y: isize, diff --git a/src/test/run-pass/issue-13264.rs b/src/test/run-pass/issue-13264.rs index e82a7602ef594..7acabf31c85a1 100644 --- a/src/test/run-pass/issue-13264.rs +++ b/src/test/run-pass/issue-13264.rs @@ -24,7 +24,7 @@ impl Deref for Root { } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct JSRef { node: *const Node } diff --git a/src/test/run-pass/issue-17897.rs b/src/test/run-pass/issue-17897.rs index 3fbdb92e90617..cf8c54fdd8086 100644 --- a/src/test/run-pass/issue-17897.rs +++ b/src/test/run-pass/issue-17897.rs @@ -12,10 +12,10 @@ use std::thunk::Thunk; -fn action(cb: Thunk) -> usize { - cb.invoke(1) +fn action(cb: Thunk<(usize,), usize>) -> usize { + cb(1) } pub fn main() { - println!("num: {}", action(Thunk::with_arg(move |u| u))); + println!("num: {}", action(Box::new(move |u| u))); } diff --git a/src/test/run-pass/issue-18188.rs b/src/test/run-pass/issue-18188.rs index cd28d6425516d..059d25173c2ad 100644 --- a/src/test/run-pass/issue-18188.rs +++ b/src/test/run-pass/issue-18188.rs @@ -16,13 +16,13 @@ use std::thunk::Thunk; pub trait Promisable: Send + Sync {} impl Promisable for T {} -pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a,Result, Result> +pub fn propagate<'a, T, E, F, G>(action: F) -> Thunk<'a, (Result,), Result> where T: Promisable + Clone + 'a, E: Promisable + Clone + 'a, F: FnOnce(&T) -> Result + Send + 'a, G: FnOnce(Result) -> Result + 'a { - Thunk::with_arg(move |result: Result| { + Box::new(move |result: Result| { match result { Ok(ref t) => action(t), Err(ref e) => Err(e.clone()), diff --git a/src/test/run-pass/issue-19100.rs b/src/test/run-pass/issue-19100.rs index 26eacd682efdd..0fd4b4394dc27 100644 --- a/src/test/run-pass/issue-19100.rs +++ b/src/test/run-pass/issue-19100.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(Copy)] +#[derive(Copy, Clone)] enum Foo { Bar, Baz diff --git a/src/test/run-pass/issue-20797.rs b/src/test/run-pass/issue-20797.rs index 45d31d4a7f168..8b5e6f837d852 100644 --- a/src/test/run-pass/issue-20797.rs +++ b/src/test/run-pass/issue-20797.rs @@ -34,7 +34,7 @@ pub trait Strategy { } /// The basic fully-recursive strategy. Nothing is pruned. -#[derive(Copy, Default)] +#[derive(Copy, Clone, Default)] pub struct Recursive; impl Strategy for Recursive { diff --git a/src/test/run-pass/issue-21296.rs b/src/test/run-pass/issue-21296.rs index 2ce36b0dd44d7..5e2ac61caa216 100644 --- a/src/test/run-pass/issue-21296.rs +++ b/src/test/run-pass/issue-21296.rs @@ -14,4 +14,8 @@ #[derive(Copy)] struct Test(*const i32); +impl Clone for Test { + fn clone(&self) -> Test { *self } +} + fn main() {} diff --git a/src/test/run-pass/issue-2190-1.rs b/src/test/run-pass/issue-2190-1.rs index b2c21a274cb83..5c84c30aa7fa3 100644 --- a/src/test/run-pass/issue-2190-1.rs +++ b/src/test/run-pass/issue-2190-1.rs @@ -18,11 +18,11 @@ use std::thunk::Thunk; static generations: usize = 1024+256+128+49; fn spawn(f: Thunk<'static>) { - Builder::new().stack_size(32 * 1024).spawn(move|| f.invoke(())); + Builder::new().stack_size(32 * 1024).spawn(move|| f()); } fn child_no(x: usize) -> Thunk<'static> { - Thunk::new(move|| { + Box::new(move|| { if x < generations { spawn(child_no(x+1)); } diff --git a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs index 8b2e1c3e149f7..8a0f04a2cf0e4 100644 --- a/src/test/run-pass/issue-22536-copy-mustnt-zero.rs +++ b/src/test/run-pass/issue-22536-copy-mustnt-zero.rs @@ -22,12 +22,14 @@ struct BufferHandle { raw: ::Buffer, } impl Copy for BufferHandle {} +impl Clone for BufferHandle { + fn clone(&self) -> BufferHandle { *self } +} enum Res {} impl Resources for Res { type Buffer = u32; } -impl Copy for Res { } fn main() { let b: BufferHandle = BufferHandle { raw: 1 }; diff --git a/src/test/run-pass/issue-2288.rs b/src/test/run-pass/issue-2288.rs index 3364fae0d6f34..d16655a68554a 100644 --- a/src/test/run-pass/issue-2288.rs +++ b/src/test/run-pass/issue-2288.rs @@ -17,7 +17,7 @@ trait clam { fn chowder(&self, y: A); } -#[derive(Copy)] +#[derive(Copy, Clone)] struct foo { x: A, } diff --git a/src/test/run-pass/issue-23550.rs b/src/test/run-pass/issue-23550.rs index 97357c1dba467..9b5ca23565e0d 100644 --- a/src/test/run-pass/issue-23550.rs +++ b/src/test/run-pass/issue-23550.rs @@ -13,7 +13,7 @@ use std::intrinsics; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Wrap(i64); // These volatile and atomic intrinsics used to cause an ICE diff --git a/src/test/run-pass/issue-2633.rs b/src/test/run-pass/issue-2633.rs index de99141c80311..5841a9ec176cd 100644 --- a/src/test/run-pass/issue-2633.rs +++ b/src/test/run-pass/issue-2633.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(Copy)] +#[derive(Copy, Clone)] struct cat { meow: extern "Rust" fn(), } @@ -23,7 +23,7 @@ fn cat() -> cat { } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct KittyInfo {kitty: cat} // Code compiles and runs successfully if we add a + before the first arg diff --git a/src/test/run-pass/issue-3121.rs b/src/test/run-pass/issue-3121.rs index 5a1fedbdccc37..777e5bf7a6ded 100644 --- a/src/test/run-pass/issue-3121.rs +++ b/src/test/run-pass/issue-3121.rs @@ -13,11 +13,11 @@ #![allow(unknown_features)] #![feature(box_syntax)] -#[derive(Copy)] +#[derive(Copy, Clone)] enum side { mayo, catsup, vinegar } -#[derive(Copy)] +#[derive(Copy, Clone)] enum order { hamburger, fries(side), shake } -#[derive(Copy)] +#[derive(Copy, Clone)] enum meal { to_go(order), for_here(order) } fn foo(m: Box, cond: bool) { diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index 0783762511761..cfdc54a362274 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -29,7 +29,7 @@ use std::iter::repeat; use std::slice; // Represents a position on a canvas. -#[derive(Copy)] +#[derive(Copy, Clone)] struct Point { x: isize, y: isize, @@ -37,13 +37,13 @@ struct Point { // Represents an offset on a canvas. (This has the same structure as a Point. // but different semantics). -#[derive(Copy)] +#[derive(Copy, Clone)] struct Size { width: isize, height: isize, } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Rect { top_left: Point, size: Size, diff --git a/src/test/run-pass/issue-3609.rs b/src/test/run-pass/issue-3609.rs index 45eb21374e298..2167a3df9766f 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -13,7 +13,6 @@ use std::thread; use std::sync::mpsc::Sender; -use std::thunk::Invoke; type RingBuffer = Vec ; type SamplesFn = Box; diff --git a/src/test/run-pass/issue-3743.rs b/src/test/run-pass/issue-3743.rs index 7f66b6b25b8d2..cd62c04a32581 100644 --- a/src/test/run-pass/issue-3743.rs +++ b/src/test/run-pass/issue-3743.rs @@ -13,7 +13,7 @@ use std::ops::Mul; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Vec2 { x: f64, y: f64 diff --git a/src/test/run-pass/issue-3753.rs b/src/test/run-pass/issue-3753.rs index bbfeb94cd9de1..e81025d846450 100644 --- a/src/test/run-pass/issue-3753.rs +++ b/src/test/run-pass/issue-3753.rs @@ -16,13 +16,13 @@ use std::f64; -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Point { x: f64, y: f64 } -#[derive(Copy)] +#[derive(Copy, Clone)] pub enum Shape { Circle(Point, f64), Rectangle(Point, Point) diff --git a/src/test/run-pass/issue-5688.rs b/src/test/run-pass/issue-5688.rs index 3c25c6dc8edd7..88ff103723c73 100644 --- a/src/test/run-pass/issue-5688.rs +++ b/src/test/run-pass/issue-5688.rs @@ -17,7 +17,7 @@ with the representation of [isize; n] and [isize] somehow, or at least failed to typecheck correctly. */ -#[derive(Copy)] +#[derive(Copy, Clone)] struct X { vec: &'static [isize] } static V: &'static [X] = &[X { vec: &[1, 2, 3] }]; diff --git a/src/test/run-pass/match-arm-statics.rs b/src/test/run-pass/match-arm-statics.rs index e21f89aee43b4..1b4dfb869d413 100644 --- a/src/test/run-pass/match-arm-statics.rs +++ b/src/test/run-pass/match-arm-statics.rs @@ -38,7 +38,7 @@ const VARIANT2_NORTH: EnumWithStructVariants = EnumWithStructVariants::Variant2 dir: Direction::North }; pub mod glfw { - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct InputState(usize); pub const RELEASE : InputState = InputState(0); diff --git a/src/test/run-pass/method-self-arg-trait.rs b/src/test/run-pass/method-self-arg-trait.rs index 8687014bfbb53..f0ca0a70acc96 100644 --- a/src/test/run-pass/method-self-arg-trait.rs +++ b/src/test/run-pass/method-self-arg-trait.rs @@ -17,7 +17,7 @@ static mut COUNT: u64 = 1; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Foo; trait Bar : Sized { diff --git a/src/test/run-pass/method-self-arg.rs b/src/test/run-pass/method-self-arg.rs index 98ab67b05afda..dfc121192228d 100644 --- a/src/test/run-pass/method-self-arg.rs +++ b/src/test/run-pass/method-self-arg.rs @@ -17,7 +17,7 @@ static mut COUNT: usize = 1; -#[derive(Copy)] +#[derive(Copy, Clone)] struct Foo; impl Foo { diff --git a/src/test/run-pass/method-two-trait-defer-resolution-2.rs b/src/test/run-pass/method-two-trait-defer-resolution-2.rs index d87ed03e94e01..2ceff22adb9eb 100644 --- a/src/test/run-pass/method-two-trait-defer-resolution-2.rs +++ b/src/test/run-pass/method-two-trait-defer-resolution-2.rs @@ -8,13 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Test that we pick which version of `Foo` to run based on whether -// the type we (ultimately) inferred for `x` is copyable or not. -// -// In this case, the two versions are both impls of same trait, and -// hence we we can resolve method even without knowing yet which -// version will run (note that the `push` occurs after the call to -// `foo()`). +// Test that when we write `x.foo()`, we do nothave to know the +// complete type of `x` in order to type-check the method call. In +// this case, we know that `x: Vec<_1>`, but we don't know what type +// `_1` is (because the call to `push` comes later). To pick between +// the impls, we would have to know `_1`, since we have to know +// whether `_1: MyCopy` or `_1 == Box`. However (and this is the +// point of the test), we don't have to pick between the two impls -- +// it is enough to know that `foo` comes from the `Foo` trait. We can +// translate the call as `Foo::foo(&x)` and let the specific impl get +// chosen later. // pretty-expanded FIXME #23616 @@ -25,25 +28,29 @@ trait Foo { fn foo(&self) -> isize; } -impl Foo for Vec { +trait MyCopy { fn foo(&self) { } } +impl MyCopy for i32 { } + +impl Foo for Vec { fn foo(&self) -> isize {1} } -impl Foo for Vec> { +impl Foo for Vec> { fn foo(&self) -> isize {2} } fn call_foo_copy() -> isize { let mut x = Vec::new(); let y = x.foo(); - x.push(0_usize); + x.push(0_i32); y } fn call_foo_other() -> isize { - let mut x: Vec> = Vec::new(); + let mut x: Vec<_> = Vec::new(); let y = x.foo(); - x.push(box 0); + let z: Box = box 0; + x.push(z); y } diff --git a/src/test/run-pass/monomorphize-abi-alignment.rs b/src/test/run-pass/monomorphize-abi-alignment.rs index 726f205f5c420..00e97ebc24e7b 100644 --- a/src/test/run-pass/monomorphize-abi-alignment.rs +++ b/src/test/run-pass/monomorphize-abi-alignment.rs @@ -18,7 +18,7 @@ * and apply the wrong instance of the method `unwrap`. */ -#[derive(Copy)] +#[derive(Copy, Clone)] struct S { i:u8, t:T } impl S { @@ -27,10 +27,10 @@ impl S { } } -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] struct A((u32, u32)); -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] struct B(u64); pub fn main() { diff --git a/src/test/run-pass/multidispatch1.rs b/src/test/run-pass/multidispatch1.rs index 0233a7ff48553..fdf9f95b274d4 100644 --- a/src/test/run-pass/multidispatch1.rs +++ b/src/test/run-pass/multidispatch1.rs @@ -16,7 +16,7 @@ trait MyTrait { fn get(&self) -> T; } -#[derive(Copy)] +#[derive(Copy, Clone)] struct MyType { dummy: usize } diff --git a/src/test/run-pass/multidispatch2.rs b/src/test/run-pass/multidispatch2.rs index 161913f6f5ddb..75c6c5ac7d165 100644 --- a/src/test/run-pass/multidispatch2.rs +++ b/src/test/run-pass/multidispatch2.rs @@ -25,7 +25,7 @@ impl MyTrait for T } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct MyType { dummy: usize } diff --git a/src/test/run-pass/newtype.rs b/src/test/run-pass/newtype.rs index fb43f041e0465..818ea4c9f2326 100644 --- a/src/test/run-pass/newtype.rs +++ b/src/test/run-pass/newtype.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[derive(Copy)] +#[derive(Copy, Clone)] struct mytype(Mytype); -#[derive(Copy)] +#[derive(Copy, Clone)] struct Mytype { compute: fn(mytype) -> isize, val: isize, diff --git a/src/test/run-pass/operator-overloading.rs b/src/test/run-pass/operator-overloading.rs index fc089839683ed..045af79189acd 100644 --- a/src/test/run-pass/operator-overloading.rs +++ b/src/test/run-pass/operator-overloading.rs @@ -13,7 +13,7 @@ use std::cmp; use std::ops; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] struct Point { x: isize, y: isize diff --git a/src/test/run-pass/out-pointer-aliasing.rs b/src/test/run-pass/out-pointer-aliasing.rs index eb0a6c95134ae..0a58411041e64 100644 --- a/src/test/run-pass/out-pointer-aliasing.rs +++ b/src/test/run-pass/out-pointer-aliasing.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Foo { f1: isize, _f2: isize, diff --git a/src/test/run-pass/overloaded-autoderef-order.rs b/src/test/run-pass/overloaded-autoderef-order.rs index fdd7a5000b2ee..6880032e69f66 100644 --- a/src/test/run-pass/overloaded-autoderef-order.rs +++ b/src/test/run-pass/overloaded-autoderef-order.rs @@ -13,7 +13,7 @@ use std::rc::Rc; use std::ops::Deref; -#[derive(Copy)] +#[derive(Copy, Clone)] struct DerefWrapper { x: X, y: Y @@ -36,7 +36,7 @@ impl Deref for DerefWrapper { mod priv_test { use std::ops::Deref; - #[derive(Copy)] + #[derive(Copy, Clone)] pub struct DerefWrapperHideX { x: X, pub y: Y diff --git a/src/test/run-pass/packed-struct-vec.rs b/src/test/run-pass/packed-struct-vec.rs index 92f57f04b10ae..9a327eb567266 100644 --- a/src/test/run-pass/packed-struct-vec.rs +++ b/src/test/run-pass/packed-struct-vec.rs @@ -13,7 +13,7 @@ use std::mem; #[repr(packed)] -#[derive(Copy, PartialEq, Debug)] +#[derive(Copy, Clone, PartialEq, Debug)] struct Foo { bar: u8, baz: u64 diff --git a/src/test/run-pass/rec-tup.rs b/src/test/run-pass/rec-tup.rs index c61c387c7812f..1644a1694269a 100644 --- a/src/test/run-pass/rec-tup.rs +++ b/src/test/run-pass/rec-tup.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] struct Point {x: isize, y: isize} type rect = (Point, Point); diff --git a/src/test/run-pass/rec.rs b/src/test/run-pass/rec.rs index 96b6b50237d73..a422aaba84b30 100644 --- a/src/test/run-pass/rec.rs +++ b/src/test/run-pass/rec.rs @@ -10,7 +10,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] struct Rect {x: isize, y: isize, w: isize, h: isize} fn f(r: Rect, x: isize, y: isize, w: isize, h: isize) { diff --git a/src/test/run-pass/regions-dependent-addr-of.rs b/src/test/run-pass/regions-dependent-addr-of.rs index 0cb70735dbac8..123806a4d9d17 100644 --- a/src/test/run-pass/regions-dependent-addr-of.rs +++ b/src/test/run-pass/regions-dependent-addr-of.rs @@ -30,7 +30,7 @@ struct B { v6: Option } -#[derive(Copy)] +#[derive(Copy, Clone)] struct C { f: isize } diff --git a/src/test/run-pass/regions-early-bound-used-in-bound-method.rs b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs index b1f9ff4de0f41..6ad8995123889 100644 --- a/src/test/run-pass/regions-early-bound-used-in-bound-method.rs +++ b/src/test/run-pass/regions-early-bound-used-in-bound-method.rs @@ -17,7 +17,7 @@ trait GetRef<'a> { fn get(&self) -> &'a isize; } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Box<'a> { t: &'a isize } diff --git a/src/test/run-pass/regions-early-bound-used-in-bound.rs b/src/test/run-pass/regions-early-bound-used-in-bound.rs index 9c2d2726a7350..6ab95d6e497bc 100644 --- a/src/test/run-pass/regions-early-bound-used-in-bound.rs +++ b/src/test/run-pass/regions-early-bound-used-in-bound.rs @@ -17,12 +17,11 @@ trait GetRef<'a, T> { fn get(&self) -> &'a T; } +#[derive(Copy, Clone)] struct Box<'a, T:'a> { t: &'a T } -impl<'a,T:'a> Copy for Box<'a,T> {} - impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { fn get(&self) -> &'a T { self.t diff --git a/src/test/run-pass/regions-early-bound-used-in-type-param.rs b/src/test/run-pass/regions-early-bound-used-in-type-param.rs index 830fb7127b9b4..dc991e9493fe4 100644 --- a/src/test/run-pass/regions-early-bound-used-in-type-param.rs +++ b/src/test/run-pass/regions-early-bound-used-in-type-param.rs @@ -17,7 +17,7 @@ trait Get { fn get(&self) -> T; } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Box { t: T } diff --git a/src/test/run-pass/regions-mock-tcx.rs b/src/test/run-pass/regions-mock-tcx.rs index c6bacac63e068..ed3cec465eff8 100644 --- a/src/test/run-pass/regions-mock-tcx.rs +++ b/src/test/run-pass/regions-mock-tcx.rs @@ -29,7 +29,7 @@ use std::mem; type Type<'tcx> = &'tcx TypeStructure<'tcx>; -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum TypeStructure<'tcx> { TypeInt, TypeFunction(Type<'tcx>, Type<'tcx>), @@ -94,20 +94,20 @@ impl<'tcx,'ast> TypeContext<'tcx, 'ast> { } } -#[derive(Copy, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash)] struct NodeId { id: usize } type Ast<'ast> = &'ast AstStructure<'ast>; -#[derive(Copy)] +#[derive(Copy, Clone)] struct AstStructure<'ast> { id: NodeId, kind: AstKind<'ast> } -#[derive(Copy)] +#[derive(Copy, Clone)] enum AstKind<'ast> { ExprInt, ExprVar(usize), diff --git a/src/test/run-pass/self-in-mut-slot-immediate-value.rs b/src/test/run-pass/self-in-mut-slot-immediate-value.rs index fa7b21a26c542..fa9ad9f6517a6 100644 --- a/src/test/run-pass/self-in-mut-slot-immediate-value.rs +++ b/src/test/run-pass/self-in-mut-slot-immediate-value.rs @@ -13,7 +13,7 @@ // pretty-expanded FIXME #23616 -#[derive(Copy)] +#[derive(Copy, Clone)] struct Value { n: isize } diff --git a/src/test/run-pass/simd-generics.rs b/src/test/run-pass/simd-generics.rs index 201da8dbc9489..867f028a3fb3c 100644 --- a/src/test/run-pass/simd-generics.rs +++ b/src/test/run-pass/simd-generics.rs @@ -16,7 +16,7 @@ use std::ops; #[simd] -#[derive(Copy)] +#[derive(Copy, Clone)] struct f32x4(f32, f32, f32, f32); fn add>(lhs: T, rhs: T) -> T { diff --git a/src/test/run-pass/small-enum-range-edge.rs b/src/test/run-pass/small-enum-range-edge.rs index a87a3072c8adb..9515da6fcbc8d 100644 --- a/src/test/run-pass/small-enum-range-edge.rs +++ b/src/test/run-pass/small-enum-range-edge.rs @@ -18,14 +18,14 @@ */ #[repr(u8)] -#[derive(Copy)] +#[derive(Copy, Clone)] enum Eu { Lu = 0, Hu = 255 } static CLu: Eu = Eu::Lu; static CHu: Eu = Eu::Hu; #[repr(i8)] -#[derive(Copy)] +#[derive(Copy, Clone)] enum Es { Ls = -128, Hs = 127 } static CLs: Es = Es::Ls; diff --git a/src/test/run-pass/struct-return.rs b/src/test/run-pass/struct-return.rs index 9e372913e0540..1ff13d4eaeacb 100644 --- a/src/test/run-pass/struct-return.rs +++ b/src/test/run-pass/struct-return.rs @@ -10,10 +10,10 @@ // // ignore-lexer-test FIXME #15883 -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Quad { a: u64, b: u64, c: u64, d: u64 } -#[derive(Copy)] +#[derive(Copy, Clone)] pub struct Floats { a: f64, b: u8, c: f64 } mod rustrt { diff --git a/src/test/run-pass/structured-compare.rs b/src/test/run-pass/structured-compare.rs index 4df802849e2fd..7974366c395fc 100644 --- a/src/test/run-pass/structured-compare.rs +++ b/src/test/run-pass/structured-compare.rs @@ -10,7 +10,7 @@ -#[derive(Copy, Debug)] +#[derive(Copy, Clone, Debug)] enum foo { large, small, } impl PartialEq for foo { diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs index 7103fa7c33e3b..447b4de450bf1 100644 --- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs +++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs @@ -77,7 +77,7 @@ fn main() { all_sync_send!(LinkedList::::new(), iter, iter_mut, into_iter); - #[derive(Copy)] + #[derive(Copy, Clone)] #[repr(usize)] #[allow(dead_code)] enum Foo { A, B, C } diff --git a/src/test/run-pass/tag-variant-disr-val.rs b/src/test/run-pass/tag-variant-disr-val.rs index affabff916490..a063801032e3d 100644 --- a/src/test/run-pass/tag-variant-disr-val.rs +++ b/src/test/run-pass/tag-variant-disr-val.rs @@ -11,7 +11,7 @@ use color::{red, green, blue, black, white, imaginary, purple, orange}; -#[derive(Copy)] +#[derive(Copy, Clone)] enum color { red = 0xff0000, green = 0x00ff00, diff --git a/src/test/run-pass/trait-coercion-generic.rs b/src/test/run-pass/trait-coercion-generic.rs index 2f33621e36c70..f9a22d5ccec6d 100644 --- a/src/test/run-pass/trait-coercion-generic.rs +++ b/src/test/run-pass/trait-coercion-generic.rs @@ -12,7 +12,7 @@ trait Trait { fn f(&self, x: T); } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: isize, y: isize, diff --git a/src/test/run-pass/trait-coercion.rs b/src/test/run-pass/trait-coercion.rs index de0a2e9e4d458..fa31d9891aaf7 100644 --- a/src/test/run-pass/trait-coercion.rs +++ b/src/test/run-pass/trait-coercion.rs @@ -17,7 +17,7 @@ trait Trait { fn f(&self); } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Struct { x: isize, y: isize, diff --git a/src/test/run-pass/traits-conditional-dispatch.rs b/src/test/run-pass/traits-conditional-dispatch.rs index 5edd3dfbc9ef5..0190b7b7b9628 100644 --- a/src/test/run-pass/traits-conditional-dispatch.rs +++ b/src/test/run-pass/traits-conditional-dispatch.rs @@ -17,16 +17,24 @@ #![allow(unknown_features)] #![feature(box_syntax)] +use std::marker::MarkerTrait; + trait Get { fn get(&self) -> Self; } -impl Get for T { - fn get(&self) -> T { *self } +trait MyCopy : MarkerTrait { fn copy(&self) -> Self; } +impl MyCopy for u16 { fn copy(&self) -> Self { *self } } +impl MyCopy for u32 { fn copy(&self) -> Self { *self } } +impl MyCopy for i32 { fn copy(&self) -> Self { *self } } +impl MyCopy for Option { fn copy(&self) -> Self { *self } } + +impl Get for T { + fn get(&self) -> T { self.copy() } } -impl Get for Box { - fn get(&self) -> Box { box get_it(&**self) } +impl Get for Box { + fn get(&self) -> Box { box get_it(&**self) } } fn get_it(t: &T) -> T { diff --git a/src/test/run-pass/ufcs-explicit-self.rs b/src/test/run-pass/ufcs-explicit-self.rs index 3a1394447f624..bd09a311b70fb 100644 --- a/src/test/run-pass/ufcs-explicit-self.rs +++ b/src/test/run-pass/ufcs-explicit-self.rs @@ -11,7 +11,7 @@ #![allow(unknown_features)] #![feature(box_syntax)] -#[derive(Copy)] +#[derive(Copy, Clone)] struct Foo { f: isize, } @@ -28,7 +28,7 @@ impl Foo { } } -#[derive(Copy)] +#[derive(Copy, Clone)] struct Bar { f: T, } diff --git a/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs new file mode 100644 index 0000000000000..37dccca1e2245 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-blanket-fn-mut.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that you can supply `&F` where `F: FnMut()`. + +// pretty-expanded FIXME #23616 + +#![feature(lang_items, unboxed_closures)] + +fn a i32>(mut f: F) -> i32 { + f() +} + +fn b(f: &mut FnMut() -> i32) -> i32 { + a(f) +} + +fn c i32>(f: &mut F) -> i32 { + a(f) +} + +fn main() { + let z: isize = 7; + + let x = b(&mut || 22); + assert_eq!(x, 22); + + let x = c(&mut || 22); + assert_eq!(x, 22); +} diff --git a/src/test/run-pass/unboxed-closures-blanket-fn.rs b/src/test/run-pass/unboxed-closures-blanket-fn.rs new file mode 100644 index 0000000000000..0f93966077bc3 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-blanket-fn.rs @@ -0,0 +1,37 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that you can supply `&F` where `F: Fn()`. + +// pretty-expanded FIXME #23616 + +#![feature(lang_items, unboxed_closures)] + +fn a i32>(f: F) -> i32 { + f() +} + +fn b(f: &Fn() -> i32) -> i32 { + a(f) +} + +fn c i32>(f: &F) -> i32 { + a(f) +} + +fn main() { + let z: isize = 7; + + let x = b(&|| 22); + assert_eq!(x, 22); + + let x = c(&|| 22); + assert_eq!(x, 22); +}