Auto merge of #23681 - alexcrichton:rollup, r=alexcrichton
This commit is contained in:
commit
593db005d4
171 changed files with 2213 additions and 1035 deletions
|
@ -1265,7 +1265,7 @@ be undesired.
|
|||
* Sending signals
|
||||
* Accessing/modifying the file system
|
||||
* Unsigned integer overflow (well-defined as wrapping)
|
||||
* Signed integer overflow (well-defined as two's complement representation
|
||||
* Signed integer overflow (well-defined as two’s complement representation
|
||||
wrapping)
|
||||
|
||||
#### Diverging functions
|
||||
|
@ -2961,10 +2961,10 @@ meaning of the operators on standard types is given here.
|
|||
: Exclusive or.
|
||||
Calls the `bitxor` method of the `std::ops::BitXor` trait.
|
||||
* `<<`
|
||||
: Logical left shift.
|
||||
: Left shift.
|
||||
Calls the `shl` method of the `std::ops::Shl` trait.
|
||||
* `>>`
|
||||
: Logical right shift.
|
||||
: Right shift.
|
||||
Calls the `shr` method of the `std::ops::Shr` trait.
|
||||
|
||||
#### Lazy boolean operators
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* [More Strings](more-strings.md)
|
||||
* [Patterns](patterns.md)
|
||||
* [Method Syntax](method-syntax.md)
|
||||
* [Associated Types](associated-types.md)
|
||||
* [Closures](closures.md)
|
||||
* [Iterators](iterators.md)
|
||||
* [Generics](generics.md)
|
||||
|
|
202
src/doc/trpl/associated-types.md
Normal file
202
src/doc/trpl/associated-types.md
Normal file
|
@ -0,0 +1,202 @@
|
|||
% Associated Types
|
||||
|
||||
Associated types are a powerful part of Rust's type system. They're related to
|
||||
the idea of a 'type family', in other words, grouping multiple types together. That
|
||||
description is a bit abstract, so let's dive right into an example. If you want
|
||||
to write a `Graph` trait, you have two types to be generic over: the node type
|
||||
and the edge type. So you might write a trait, `Graph<N, E>`, that looks like
|
||||
this:
|
||||
|
||||
```rust
|
||||
trait Graph<N, E> {
|
||||
fn has_edge(&self, &N, &N) -> bool;
|
||||
fn edges(&self, &N) -> Vec<E>;
|
||||
// etc
|
||||
}
|
||||
```
|
||||
|
||||
While this sort of works, it ends up being awkward. For example, any function
|
||||
that wants to take a `Graph` as a parameter now _also_ needs to be generic over
|
||||
the `N`ode and `E`dge types too:
|
||||
|
||||
```rust,ignore
|
||||
fn distance<N, E, G: Graph<N, E>>(graph: &G, start: &N, end: &N) -> u32 { ... }
|
||||
```
|
||||
|
||||
Our distance calculation works regardless of our `Edge` type, so the `E` stuff in
|
||||
this signature is just a distraction.
|
||||
|
||||
What we really want to say is that a certain `E`dge and `N`ode type come together
|
||||
to form each kind of `Graph`. We can do that with associated types:
|
||||
|
||||
```rust
|
||||
trait Graph {
|
||||
type N;
|
||||
type E;
|
||||
|
||||
fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
||||
fn edges(&self, &Self::N) -> Vec<Self::E>;
|
||||
// etc
|
||||
}
|
||||
```
|
||||
|
||||
Now, our clients can be abstract over a given `Graph`:
|
||||
|
||||
```rust,ignore
|
||||
fn distance<G: Graph>(graph: &G, start: &G::N, end: &G::N) -> uint { ... }
|
||||
```
|
||||
|
||||
No need to deal with the `E`dge type here!
|
||||
|
||||
Let's go over all this in more detail.
|
||||
|
||||
## Defining associated types
|
||||
|
||||
Let's build that `Graph` trait. Here's the definition:
|
||||
|
||||
```rust
|
||||
trait Graph {
|
||||
type N;
|
||||
type E;
|
||||
|
||||
fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
||||
fn edges(&self, &Self::N) -> Vec<Self::E>;
|
||||
}
|
||||
```
|
||||
|
||||
Simple enough. Associated types use the `type` keyword, and go inside the body
|
||||
of the trait, with the functions.
|
||||
|
||||
These `type` declarations can have all the same thing as functions do. For example,
|
||||
if we wanted our `N` type to implement `Display`, so we can print the nodes out,
|
||||
we could do this:
|
||||
|
||||
```rust
|
||||
use std::fmt;
|
||||
|
||||
trait Graph {
|
||||
type N: fmt::Display;
|
||||
type E;
|
||||
|
||||
fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
||||
fn edges(&self, &Self::N) -> Vec<Self::E>;
|
||||
}
|
||||
```
|
||||
|
||||
## Implementing associated types
|
||||
|
||||
Just like any trait, traits that use associated types use the `impl` keyword to
|
||||
provide implementations. Here's a simple implementation of Graph:
|
||||
|
||||
```rust
|
||||
# trait Graph {
|
||||
# type N;
|
||||
# type E;
|
||||
# fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
||||
# fn edges(&self, &Self::N) -> Vec<Self::E>;
|
||||
# }
|
||||
struct Node;
|
||||
|
||||
struct Edge;
|
||||
|
||||
struct MyGraph;
|
||||
|
||||
impl Graph for MyGraph {
|
||||
type N = Node;
|
||||
type E = Edge;
|
||||
|
||||
fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn edges(&self, n: &Node) -> Vec<Edge> {
|
||||
Vec::new()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This silly implementation always returns `true` and an empty `Vec<Edge>`, but it
|
||||
gives you an idea of how to implement this kind of thing. We first need three
|
||||
`struct`s, one for the graph, one for the node, and one for the edge. If it made
|
||||
more sense to use a different type, that would work as well, we're just going to
|
||||
use `struct`s for all three here.
|
||||
|
||||
Next is the `impl` line, which is just like implementing any other trait.
|
||||
|
||||
From here, we use `=` to define our associated types. The name the trait uses
|
||||
goes on the left of the `=`, and the concrete type we're `impl`ementing this
|
||||
for goes on the right. Finally, we use the concrete types in our function
|
||||
declarations.
|
||||
|
||||
## Trait objects with associated types
|
||||
|
||||
There’s one more bit of syntax we should talk about: trait objects. If you
|
||||
try to create a trait object from an associated type, like this:
|
||||
|
||||
```rust,ignore
|
||||
# trait Graph {
|
||||
# type N;
|
||||
# type E;
|
||||
# fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
||||
# fn edges(&self, &Self::N) -> Vec<Self::E>;
|
||||
# }
|
||||
# struct Node;
|
||||
# struct Edge;
|
||||
# struct MyGraph;
|
||||
# impl Graph for MyGraph {
|
||||
# type N = Node;
|
||||
# type E = Edge;
|
||||
# fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
|
||||
# true
|
||||
# }
|
||||
# fn edges(&self, n: &Node) -> Vec<Edge> {
|
||||
# Vec::new()
|
||||
# }
|
||||
# }
|
||||
let graph = MyGraph;
|
||||
let obj = Box::new(graph) as Box<Graph>;
|
||||
```
|
||||
|
||||
You’ll get two errors:
|
||||
|
||||
```text
|
||||
error: the value of the associated type `E` (from the trait `main::Graph`) must
|
||||
be specified [E0191]
|
||||
let obj = Box::new(graph) as Box<Graph>;
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
24:44 error: the value of the associated type `N` (from the trait
|
||||
`main::Graph`) must be specified [E0191]
|
||||
let obj = Box::new(graph) as Box<Graph>;
|
||||
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
We can’t create a trait object like this, becuase we don’t know the associated
|
||||
types. Instead, we can write this:
|
||||
|
||||
```rust
|
||||
# trait Graph {
|
||||
# type N;
|
||||
# type E;
|
||||
# fn has_edge(&self, &Self::N, &Self::N) -> bool;
|
||||
# fn edges(&self, &Self::N) -> Vec<Self::E>;
|
||||
# }
|
||||
# struct Node;
|
||||
# struct Edge;
|
||||
# struct MyGraph;
|
||||
# impl Graph for MyGraph {
|
||||
# type N = Node;
|
||||
# type E = Edge;
|
||||
# fn has_edge(&self, n1: &Node, n2: &Node) -> bool {
|
||||
# true
|
||||
# }
|
||||
# fn edges(&self, n: &Node) -> Vec<Edge> {
|
||||
# Vec::new()
|
||||
# }
|
||||
# }
|
||||
let graph = MyGraph;
|
||||
let obj = Box::new(graph) as Box<Graph<N=Node, E=Edge>>;
|
||||
```
|
||||
|
||||
The `N=Node` syntax allows us to provide a concrete type, `Node`, for the `N`
|
||||
type parameter. Same with `E=Edge`. If we didn’t proide this constraint, we
|
||||
couldn’t be sure which `impl` to match this trait object to.
|
|
@ -513,8 +513,8 @@ Otherwise, it is an error to elide an output lifetime.
|
|||
|
||||
### Examples
|
||||
|
||||
Here are some examples of functions with elided lifetimes, and the version of
|
||||
what the elided lifetimes are expand to:
|
||||
Here are some examples of functions with elided lifetimes. We've paired each
|
||||
example of an elided lifetime with its expanded form.
|
||||
|
||||
```{rust,ignore}
|
||||
fn print(s: &str); // elided
|
||||
|
|
|
@ -197,15 +197,16 @@ use std::ptr;
|
|||
|
||||
// Define a wrapper around the handle returned by the foreign code.
|
||||
// Unique<T> has the same semantics as Box<T>
|
||||
pub struct Unique<T> {
|
||||
//
|
||||
// NB: For simplicity and correctness, we require that T has kind Send
|
||||
// (owned boxes relax this restriction).
|
||||
pub struct Unique<T: Send> {
|
||||
// It contains a single raw, mutable pointer to the object in question.
|
||||
ptr: *mut T
|
||||
}
|
||||
|
||||
// Implement methods for creating and using the values in the box.
|
||||
|
||||
// NB: For simplicity and correctness, we require that T has kind Send
|
||||
// (owned boxes relax this restriction).
|
||||
impl<T: Send> Unique<T> {
|
||||
pub fn new(value: T) -> Unique<T> {
|
||||
unsafe {
|
||||
|
@ -239,11 +240,11 @@ impl<T: Send> Unique<T> {
|
|||
// Unique<T>, making the struct manage the raw pointer: when the
|
||||
// struct goes out of scope, it will automatically free the raw pointer.
|
||||
//
|
||||
// NB: This is an unsafe destructor, because rustc will not normally
|
||||
// allow destructors to be associated with parameterized types, due to
|
||||
// bad interaction with managed boxes. (With the Send restriction,
|
||||
// we don't have this problem.) Note that the `#[unsafe_destructor]`
|
||||
// feature gate is required to use unsafe destructors.
|
||||
// NB: This is an unsafe destructor; rustc will not normally allow
|
||||
// destructors to be associated with parameterized types (due to
|
||||
// historically failing to check them soundly). Note that the
|
||||
// `#[unsafe_destructor]` feature gate is currently required to use
|
||||
// unsafe destructors.
|
||||
#[unsafe_destructor]
|
||||
impl<T: Send> Drop for Unique<T> {
|
||||
fn drop(&mut self) {
|
||||
|
|
|
@ -165,6 +165,16 @@ void posix88_consts() {
|
|||
put_const(S_IWUSR, int);
|
||||
put_const(S_IRUSR, int);
|
||||
|
||||
put_const(S_IRWXG, int);
|
||||
put_const(S_IXGRP, int);
|
||||
put_const(S_IWGRP, int);
|
||||
put_const(S_IRGRP, int);
|
||||
|
||||
put_const(S_IRWXO, int);
|
||||
put_const(S_IXOTH, int);
|
||||
put_const(S_IWOTH, int);
|
||||
put_const(S_IROTH, int);
|
||||
|
||||
#ifdef F_OK
|
||||
put_const(F_OK, int);
|
||||
#endif
|
||||
|
|
|
@ -321,7 +321,7 @@ impl<T: Send + Sync + Clone> Arc<T> {
|
|||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Sync + Send> Drop for Arc<T> {
|
||||
impl<T> Drop for Arc<T> {
|
||||
/// Drops the `Arc<T>`.
|
||||
///
|
||||
/// This will decrement the strong reference count. If the strong reference
|
||||
|
@ -388,7 +388,7 @@ impl<T: Sync + Send> Drop for Arc<T> {
|
|||
|
||||
#[unstable(feature = "alloc",
|
||||
reason = "Weak pointers may not belong in this module.")]
|
||||
impl<T: Sync + Send> Weak<T> {
|
||||
impl<T> Weak<T> {
|
||||
/// Upgrades a weak reference to a strong reference.
|
||||
///
|
||||
/// Upgrades the `Weak<T>` reference to an `Arc<T>`, if possible.
|
||||
|
@ -454,7 +454,7 @@ impl<T: Sync + Send> Clone for Weak<T> {
|
|||
|
||||
#[unsafe_destructor]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: Sync + Send> Drop for Weak<T> {
|
||||
impl<T> Drop for Weak<T> {
|
||||
/// Drops the `Weak<T>`.
|
||||
///
|
||||
/// This will decrement the weak reference count.
|
||||
|
|
|
@ -429,7 +429,8 @@ impl<T> TypedArenaChunk<T> {
|
|||
// Destroy the next chunk.
|
||||
let next = self.next;
|
||||
let size = calculate_size::<T>(self.capacity);
|
||||
deallocate(self as *mut TypedArenaChunk<T> as *mut u8, size,
|
||||
let self_ptr: *mut TypedArenaChunk<T> = self;
|
||||
deallocate(self_ptr as *mut u8, size,
|
||||
mem::min_align_of::<TypedArenaChunk<T>>());
|
||||
if !next.is_null() {
|
||||
let capacity = (*next).capacity;
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
html_playground_url = "http://play.rust-lang.org/")]
|
||||
#![doc(test(no_crate_inject))]
|
||||
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
#![feature(alloc)]
|
||||
#![feature(box_syntax)]
|
||||
#![feature(box_patterns)]
|
||||
|
|
|
@ -1199,8 +1199,8 @@ impl<T: PartialEq> Vec<T> {
|
|||
|
||||
// Avoid bounds checks by using unsafe pointers.
|
||||
let p = self.as_mut_ptr();
|
||||
let mut r = 1;
|
||||
let mut w = 1;
|
||||
let mut r: usize = 1;
|
||||
let mut w: usize = 1;
|
||||
|
||||
while r < ln {
|
||||
let p_r = p.offset(r as isize);
|
||||
|
|
|
@ -43,8 +43,6 @@ struct Counter<'a, 'b> {
|
|||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
|
||||
type Output = bool;
|
||||
|
||||
extern "rust-call" fn call_mut(&mut self, (&x,): (&'c i32,)) -> bool {
|
||||
assert_eq!(x, self.expected[*self.i]);
|
||||
*self.i += 1;
|
||||
|
@ -52,6 +50,14 @@ impl<'a, 'b, 'c> FnMut<(&'c i32,)> for Counter<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b, 'c> FnOnce<(&'c i32,)> for Counter<'a, 'b> {
|
||||
type Output = bool;
|
||||
|
||||
extern "rust-call" fn call_once(mut self, args: (&'c i32,)) -> bool {
|
||||
self.call_mut(args)
|
||||
}
|
||||
}
|
||||
|
||||
fn check<F>(a: &[i32], b: &[i32], expected: &[i32], f: F) where
|
||||
// FIXME Replace Counter with `Box<FnMut(_) -> _>`
|
||||
F: FnOnce(&BTreeSet<i32>, &BTreeSet<i32>, Counter) -> bool,
|
||||
|
|
|
@ -82,11 +82,11 @@ use marker::Sized;
|
|||
// Any trait
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// The `Any` trait is implemented by all `'static` types, and can be used for
|
||||
/// dynamic typing
|
||||
/// A type to emulate dynamic typing. See the [module-level documentation][mod] for more details.
|
||||
///
|
||||
/// Every type with no non-`'static` references implements `Any`, so `Any` can
|
||||
/// be used as a trait object to emulate the effects dynamic typing.
|
||||
/// Every type with no non-`'static` references implements `Any`.
|
||||
///
|
||||
/// [mod]: ../index.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Any: 'static {
|
||||
/// Get the `TypeId` of `self`
|
||||
|
|
|
@ -713,7 +713,11 @@ impl<T> UnsafeCell<T> {
|
|||
/// ```
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn get(&self) -> *mut T { &self.value as *const T as *mut T }
|
||||
pub fn get(&self) -> *mut T {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
&self.value as *const T as *mut T
|
||||
}
|
||||
|
||||
/// Unwraps the value
|
||||
///
|
||||
|
|
|
@ -27,6 +27,14 @@ use marker::Sized;
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub trait Clone : Sized {
|
||||
/// Returns a copy of the value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let hello = "Hello"; // &str implements Clone
|
||||
///
|
||||
/// assert_eq!("Hello", hello.clone());
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn clone(&self) -> Self;
|
||||
|
||||
|
|
|
@ -833,6 +833,8 @@ impl<T> Pointer for *const T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T> Pointer for *mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
Pointer::fmt(&(*self as *const T), f)
|
||||
}
|
||||
}
|
||||
|
@ -840,6 +842,8 @@ impl<T> Pointer for *mut T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Pointer for &'a T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
Pointer::fmt(&(*self as *const T), f)
|
||||
}
|
||||
}
|
||||
|
@ -847,6 +851,8 @@ impl<'a, T> Pointer for &'a T {
|
|||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<'a, T> Pointer for &'a mut T {
|
||||
fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
Pointer::fmt(&(&**self as *const T), f)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// FIXME: #6220 Implement floating point formatting
|
||||
|
||||
#![allow(unsigned_negation)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
use fmt;
|
||||
use iter::IteratorExt;
|
||||
|
|
|
@ -182,6 +182,8 @@ mod impls {
|
|||
}
|
||||
|
||||
fn hash_slice<H: Hasher>(data: &[$ty], state: &mut H) {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
let newlen = data.len() * ::$ty::BYTES as usize;
|
||||
let ptr = data.as_ptr() as *const u8;
|
||||
state.write(unsafe { slice::from_raw_parts(ptr, newlen) })
|
||||
|
|
|
@ -313,6 +313,8 @@ pub fn drop<T>(_x: T) { }
|
|||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
ptr::read(src as *const T as *const U)
|
||||
}
|
||||
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i16")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
int_module! { i16, 16 }
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i32")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
int_module! { i32, 32 }
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i64")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
int_module! { i64, 64 }
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "i8")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
int_module! { i8, 8 }
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![doc(hidden)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
macro_rules! int_module { ($T:ty, $bits:expr) => (
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "isize")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
int_module! { isize, 32 }
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![allow(missing_docs)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
use self::wrapping::{OverflowingOps, WrappingOps};
|
||||
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u16")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
uint_module! { u16, i16, 16 }
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u32")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
uint_module! { u32, i32, 32 }
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u64")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
uint_module! { u64, i64, 64 }
|
||||
|
|
|
@ -12,5 +12,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "u8")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
uint_module! { u8, i8, 8 }
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
// except according to those terms.
|
||||
|
||||
#![doc(hidden)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
macro_rules! uint_module { ($T:ty, $T_SIGNED:ty, $bits:expr) => (
|
||||
|
||||
|
|
|
@ -16,5 +16,6 @@
|
|||
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
#![doc(primitive = "usize")]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
uint_module! { usize, isize, ::isize::BITS }
|
||||
|
|
|
@ -1148,6 +1148,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
|
|||
#[lang="fn"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_paren_sugar]
|
||||
#[cfg(stage0)]
|
||||
pub trait Fn<Args> {
|
||||
/// The returned type after the call operator is used.
|
||||
type Output;
|
||||
|
@ -1156,10 +1157,21 @@ pub trait Fn<Args> {
|
|||
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes an immutable receiver.
|
||||
#[lang="fn"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_paren_sugar]
|
||||
#[cfg(not(stage0))]
|
||||
pub trait Fn<Args> : FnMut<Args> {
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes a mutable receiver.
|
||||
#[lang="fn_mut"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_paren_sugar]
|
||||
#[cfg(stage0)]
|
||||
pub trait FnMut<Args> {
|
||||
/// The returned type after the call operator is used.
|
||||
type Output;
|
||||
|
@ -1168,6 +1180,16 @@ pub trait FnMut<Args> {
|
|||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes a mutable receiver.
|
||||
#[lang="fn_mut"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[rustc_paren_sugar]
|
||||
#[cfg(not(stage0))]
|
||||
pub trait FnMut<Args> : FnOnce<Args> {
|
||||
/// This is called when the call operator is used.
|
||||
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
/// A version of the call operator that takes a by-value receiver.
|
||||
#[lang="fn_once"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
|
@ -1180,6 +1202,7 @@ pub trait FnOnce<Args> {
|
|||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<F: ?Sized, A> FnMut<A> for F
|
||||
where F : Fn<A>
|
||||
{
|
||||
|
@ -1190,6 +1213,7 @@ impl<F: ?Sized, A> FnMut<A> for F
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<F,A> FnOnce<A> for F
|
||||
where F : FnMut<A>
|
||||
{
|
||||
|
|
|
@ -529,7 +529,7 @@ impl<T: ?Sized> Unique<T> {
|
|||
/// Create a new `Unique`.
|
||||
#[unstable(feature = "unique")]
|
||||
pub unsafe fn new(ptr: *mut T) -> Unique<T> {
|
||||
Unique { pointer: NonZero::new(ptr as *const T), _marker: PhantomData }
|
||||
Unique { pointer: NonZero::new(ptr), _marker: PhantomData }
|
||||
}
|
||||
|
||||
/// Dereference the content.
|
||||
|
|
|
@ -28,8 +28,9 @@ use iter::ExactSizeIterator;
|
|||
use iter::{Map, Iterator, IteratorExt, DoubleEndedIterator};
|
||||
use marker::Sized;
|
||||
use mem;
|
||||
#[allow(deprecated)]
|
||||
use num::Int;
|
||||
use ops::{Fn, FnMut};
|
||||
use ops::{Fn, FnMut, FnOnce};
|
||||
use option::Option::{self, None, Some};
|
||||
use raw::{Repr, Slice};
|
||||
use result::Result::{self, Ok, Err};
|
||||
|
@ -261,7 +262,7 @@ pub unsafe fn from_utf8_unchecked<'a>(v: &'a [u8]) -> &'a str {
|
|||
reason = "use std::ffi::c_str_to_bytes + str::from_utf8")]
|
||||
pub unsafe fn from_c_str(s: *const i8) -> &'static str {
|
||||
let s = s as *const u8;
|
||||
let mut len = 0;
|
||||
let mut len: usize = 0;
|
||||
while *s.offset(len as isize) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
|
@ -541,6 +542,7 @@ delegate_iter!{exact u8 : Bytes<'a>}
|
|||
#[derive(Copy, Clone)]
|
||||
struct BytesDeref;
|
||||
|
||||
#[cfg(stage0)]
|
||||
impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
||||
type Output = u8;
|
||||
|
||||
|
@ -550,6 +552,32 @@ impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a> Fn<(&'a u8,)> for BytesDeref {
|
||||
#[inline]
|
||||
extern "rust-call" fn call(&self, (ptr,): (&'a u8,)) -> u8 {
|
||||
*ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a> FnMut<(&'a u8,)> for BytesDeref {
|
||||
#[inline]
|
||||
extern "rust-call" fn call_mut(&mut self, (ptr,): (&'a u8,)) -> u8 {
|
||||
Fn::call(&*self, (ptr,))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
impl<'a> FnOnce<(&'a u8,)> for BytesDeref {
|
||||
type Output = u8;
|
||||
|
||||
#[inline]
|
||||
extern "rust-call" fn call_once(self, (ptr,): (&'a u8,)) -> u8 {
|
||||
Fn::call(&self, (ptr,))
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over the substrings of a string, separated by `sep`.
|
||||
struct CharSplits<'a, P: Pattern<'a>> {
|
||||
/// The slice remaining to be iterated
|
||||
|
|
|
@ -95,7 +95,7 @@ fn test_transmute() {
|
|||
trait Foo { fn dummy(&self) { } }
|
||||
impl Foo for int {}
|
||||
|
||||
let a = box 100 as Box<Foo>;
|
||||
let a = box 100isize as Box<Foo>;
|
||||
unsafe {
|
||||
let x: ::core::raw::TraitObject = transmute(a);
|
||||
assert!(*(x.data as *const int) == 100);
|
||||
|
|
|
@ -84,9 +84,9 @@ fn test_as_ref() {
|
|||
assert_eq!(q.as_ref().unwrap(), &2);
|
||||
|
||||
// Lifetime inference
|
||||
let u = 2;
|
||||
let u = 2isize;
|
||||
{
|
||||
let p: *const int = &u as *const _;
|
||||
let p = &u as *const int;
|
||||
assert_eq!(p.as_ref().unwrap(), &2);
|
||||
}
|
||||
}
|
||||
|
@ -102,9 +102,9 @@ fn test_as_mut() {
|
|||
assert!(q.as_mut().unwrap() == &mut 2);
|
||||
|
||||
// Lifetime inference
|
||||
let mut u = 2;
|
||||
let mut u = 2isize;
|
||||
{
|
||||
let p: *mut int = &mut u as *mut _;
|
||||
let p = &mut u as *mut int;
|
||||
assert!(p.as_mut().unwrap() == &mut 2);
|
||||
}
|
||||
}
|
||||
|
@ -170,9 +170,9 @@ fn test_set_memory() {
|
|||
|
||||
#[test]
|
||||
fn test_unsized_unique() {
|
||||
let xs: &mut [_] = &mut [1, 2, 3];
|
||||
let ptr = unsafe { Unique::new(xs as *mut [_]) };
|
||||
let xs: &mut [i32] = &mut [1, 2, 3];
|
||||
let ptr = unsafe { Unique::new(xs as *mut [i32]) };
|
||||
let ys = unsafe { &mut **ptr };
|
||||
let zs: &mut [_] = &mut [1, 2, 3];
|
||||
let zs: &mut [i32] = &mut [1, 2, 3];
|
||||
assert!(ys == zs);
|
||||
}
|
||||
|
|
|
@ -2439,6 +2439,7 @@ pub mod consts {
|
|||
}
|
||||
pub mod posix88 {
|
||||
use types::os::arch::c95::c_int;
|
||||
use types::os::arch::posix88::mode_t;
|
||||
|
||||
pub const O_RDONLY : c_int = 0;
|
||||
pub const O_WRONLY : c_int = 1;
|
||||
|
@ -2461,6 +2462,14 @@ pub mod consts {
|
|||
pub const S_IXUSR : c_int = 64;
|
||||
pub const S_IWUSR : c_int = 128;
|
||||
pub const S_IRUSR : c_int = 256;
|
||||
pub const S_IRWXG : mode_t = 56;
|
||||
pub const S_IXGRP : mode_t = 8;
|
||||
pub const S_IWGRP : mode_t = 16;
|
||||
pub const S_IRGRP : mode_t = 32;
|
||||
pub const S_IRWXO : mode_t = 7;
|
||||
pub const S_IXOTH : mode_t = 1;
|
||||
pub const S_IWOTH : mode_t = 2;
|
||||
pub const S_IROTH : mode_t = 4;
|
||||
pub const F_OK : c_int = 0;
|
||||
pub const R_OK : c_int = 4;
|
||||
pub const W_OK : c_int = 2;
|
||||
|
@ -2811,6 +2820,14 @@ pub mod consts {
|
|||
pub const S_IXUSR : mode_t = 64;
|
||||
pub const S_IWUSR : mode_t = 128;
|
||||
pub const S_IRUSR : mode_t = 256;
|
||||
pub const S_IRWXG : mode_t = 56;
|
||||
pub const S_IXGRP : mode_t = 8;
|
||||
pub const S_IWGRP : mode_t = 16;
|
||||
pub const S_IRGRP : mode_t = 32;
|
||||
pub const S_IRWXO : mode_t = 7;
|
||||
pub const S_IXOTH : mode_t = 1;
|
||||
pub const S_IWOTH : mode_t = 2;
|
||||
pub const S_IROTH : mode_t = 4;
|
||||
pub const F_OK : c_int = 0;
|
||||
pub const R_OK : c_int = 4;
|
||||
pub const W_OK : c_int = 2;
|
||||
|
@ -3024,6 +3041,14 @@ pub mod consts {
|
|||
pub const S_IXUSR : mode_t = 64;
|
||||
pub const S_IWUSR : mode_t = 128;
|
||||
pub const S_IRUSR : mode_t = 256;
|
||||
pub const S_IRWXG : mode_t = 56;
|
||||
pub const S_IXGRP : mode_t = 8;
|
||||
pub const S_IWGRP : mode_t = 16;
|
||||
pub const S_IRGRP : mode_t = 32;
|
||||
pub const S_IRWXO : mode_t = 7;
|
||||
pub const S_IXOTH : mode_t = 1;
|
||||
pub const S_IWOTH : mode_t = 2;
|
||||
pub const S_IROTH : mode_t = 4;
|
||||
pub const F_OK : c_int = 0;
|
||||
pub const R_OK : c_int = 4;
|
||||
pub const W_OK : c_int = 2;
|
||||
|
@ -3752,6 +3777,14 @@ pub mod consts {
|
|||
pub const S_IXUSR : mode_t = 64;
|
||||
pub const S_IWUSR : mode_t = 128;
|
||||
pub const S_IRUSR : mode_t = 256;
|
||||
pub const S_IRWXG : mode_t = 56;
|
||||
pub const S_IXGRP : mode_t = 8;
|
||||
pub const S_IWGRP : mode_t = 16;
|
||||
pub const S_IRGRP : mode_t = 32;
|
||||
pub const S_IRWXO : mode_t = 7;
|
||||
pub const S_IXOTH : mode_t = 1;
|
||||
pub const S_IWOTH : mode_t = 2;
|
||||
pub const S_IROTH : mode_t = 4;
|
||||
pub const F_OK : c_int = 0;
|
||||
pub const R_OK : c_int = 4;
|
||||
pub const W_OK : c_int = 2;
|
||||
|
@ -4198,6 +4231,14 @@ pub mod consts {
|
|||
pub const S_IXUSR : mode_t = 64;
|
||||
pub const S_IWUSR : mode_t = 128;
|
||||
pub const S_IRUSR : mode_t = 256;
|
||||
pub const S_IRWXG : mode_t = 56;
|
||||
pub const S_IXGRP : mode_t = 8;
|
||||
pub const S_IWGRP : mode_t = 16;
|
||||
pub const S_IRGRP : mode_t = 32;
|
||||
pub const S_IRWXO : mode_t = 7;
|
||||
pub const S_IXOTH : mode_t = 1;
|
||||
pub const S_IWOTH : mode_t = 2;
|
||||
pub const S_IROTH : mode_t = 4;
|
||||
pub const F_OK : c_int = 0;
|
||||
pub const R_OK : c_int = 4;
|
||||
pub const W_OK : c_int = 2;
|
||||
|
@ -4610,6 +4651,14 @@ pub mod consts {
|
|||
pub const S_IXUSR : mode_t = 64;
|
||||
pub const S_IWUSR : mode_t = 128;
|
||||
pub const S_IRUSR : mode_t = 256;
|
||||
pub const S_IRWXG : mode_t = 56;
|
||||
pub const S_IXGRP : mode_t = 8;
|
||||
pub const S_IWGRP : mode_t = 16;
|
||||
pub const S_IRGRP : mode_t = 32;
|
||||
pub const S_IRWXO : mode_t = 7;
|
||||
pub const S_IXOTH : mode_t = 1;
|
||||
pub const S_IWOTH : mode_t = 2;
|
||||
pub const S_IROTH : mode_t = 4;
|
||||
pub const F_OK : c_int = 0;
|
||||
pub const R_OK : c_int = 4;
|
||||
pub const W_OK : c_int = 2;
|
||||
|
|
|
@ -304,10 +304,10 @@ pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) {
|
|||
// Completely remove the local logger from TLS in case anyone attempts to
|
||||
// frob the slot while we're doing the logging. This will destroy any logger
|
||||
// set during logging.
|
||||
let mut logger = LOCAL_LOGGER.with(|s| {
|
||||
let mut logger: Box<Logger + Send> = LOCAL_LOGGER.with(|s| {
|
||||
s.borrow_mut().take()
|
||||
}).unwrap_or_else(|| {
|
||||
box DefaultLogger { handle: io::stderr() } as Box<Logger + Send>
|
||||
box DefaultLogger { handle: io::stderr() }
|
||||
});
|
||||
logger.log(&LogRecord {
|
||||
level: LogLevel(level),
|
||||
|
@ -443,7 +443,7 @@ fn init() {
|
|||
DIRECTIVES = boxed::into_raw(box directives);
|
||||
|
||||
// Schedule the cleanup for the globals for when the runtime exits.
|
||||
rt::at_exit(move || {
|
||||
let _ = rt::at_exit(move || {
|
||||
let _g = LOCK.lock();
|
||||
assert!(!DIRECTIVES.is_null());
|
||||
let _directives = Box::from_raw(DIRECTIVES);
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
//! Generating numbers between two others.
|
||||
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
// this is surprisingly complicated to be both generic & correct
|
||||
|
||||
use core::prelude::{PartialOrd};
|
||||
|
|
|
@ -447,6 +447,7 @@ impl Rng for Isaac64Rng {
|
|||
|
||||
#[inline]
|
||||
fn next_u64(&mut self) -> u64 {
|
||||
#![allow(trivial_numeric_casts)]
|
||||
if self.cnt == 0 {
|
||||
// make some more numbers
|
||||
self.isaac64();
|
||||
|
|
|
@ -352,8 +352,8 @@ pub mod reader {
|
|||
let i = (val >> 28) as uint;
|
||||
let (shift, mask) = SHIFT_MASK_TABLE[i];
|
||||
Ok(Res {
|
||||
val: ((val >> shift) & mask) as uint,
|
||||
next: start + (((32 - shift) >> 3) as uint)
|
||||
val: ((val >> shift) & mask) as usize,
|
||||
next: start + ((32 - shift) >> 3),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -573,7 +573,7 @@ pub mod reader {
|
|||
0 => doc_as_u8(r_doc) as u64,
|
||||
1 => doc_as_u16(r_doc) as u64,
|
||||
2 => doc_as_u32(r_doc) as u64,
|
||||
3 => doc_as_u64(r_doc) as u64,
|
||||
3 => doc_as_u64(r_doc),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
#![feature(into_cow)]
|
||||
#![cfg_attr(test, feature(test))]
|
||||
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
extern crate arena;
|
||||
extern crate flate;
|
||||
extern crate fmt_macros;
|
||||
|
|
|
@ -100,6 +100,17 @@ declare_lint! {
|
|||
"detects transmutes of fat pointers"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub TRIVIAL_CASTS,
|
||||
Warn,
|
||||
"detects trivial casts which could be removed"
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
pub TRIVIAL_NUMERIC_CASTS,
|
||||
Warn,
|
||||
"detects trivial casts of numeric types which could be removed"
|
||||
}
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// which are used by other parts of the compiler.
|
||||
#[derive(Copy)]
|
||||
|
@ -121,7 +132,9 @@ impl LintPass for HardwiredLints {
|
|||
STABLE_FEATURES,
|
||||
UNKNOWN_CRATE_TYPES,
|
||||
VARIANT_SIZE_DIFFERENCES,
|
||||
FAT_PTR_TRANSMUTES
|
||||
FAT_PTR_TRANSMUTES,
|
||||
TRIVIAL_CASTS,
|
||||
TRIVIAL_NUMERIC_CASTS
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
use super::{CombinedSnapshot, cres, InferCtxt, HigherRankedType, SkolemizationMap};
|
||||
use super::combine::{Combine, Combineable};
|
||||
|
||||
use middle::subst;
|
||||
use middle::ty::{self, Binder};
|
||||
use middle::ty_fold::{self, TypeFoldable};
|
||||
use syntax::codemap::Span;
|
||||
|
@ -455,6 +456,63 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Constructs and returns a substitution that, for a given type
|
||||
/// scheme parameterized by `generics`, will replace every generic
|
||||
/// parmeter in the type with a skolemized type/region (which one can
|
||||
/// think of as a "fresh constant", except at the type/region level of
|
||||
/// reasoning).
|
||||
///
|
||||
/// Since we currently represent bound/free type parameters in the
|
||||
/// same way, this only has an effect on regions.
|
||||
///
|
||||
/// (Note that unlike a substitution from `ty::construct_free_substs`,
|
||||
/// this inserts skolemized regions rather than free regions; this
|
||||
/// allows one to use `fn leak_check` to catch attmepts to unify the
|
||||
/// skolemized regions with e.g. the `'static` lifetime)
|
||||
pub fn construct_skolemized_substs<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
-> (subst::Substs<'tcx>, SkolemizationMap)
|
||||
{
|
||||
let mut map = FnvHashMap();
|
||||
|
||||
// map T => T
|
||||
let mut types = subst::VecPerParamSpace::empty();
|
||||
push_types_from_defs(infcx.tcx, &mut types, generics.types.as_slice());
|
||||
|
||||
// map early- or late-bound 'a => fresh 'a
|
||||
let mut regions = subst::VecPerParamSpace::empty();
|
||||
push_region_params(infcx, &mut map, &mut regions, generics.regions.as_slice(), snapshot);
|
||||
|
||||
let substs = subst::Substs { types: types,
|
||||
regions: subst::NonerasedRegions(regions) };
|
||||
return (substs, map);
|
||||
|
||||
fn push_region_params<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
|
||||
map: &mut SkolemizationMap,
|
||||
regions: &mut subst::VecPerParamSpace<ty::Region>,
|
||||
region_params: &[ty::RegionParameterDef],
|
||||
snapshot: &CombinedSnapshot)
|
||||
{
|
||||
for r in region_params {
|
||||
let br = r.to_bound_region();
|
||||
let skol_var = infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot);
|
||||
let sanity_check = map.insert(br, skol_var);
|
||||
assert!(sanity_check.is_none());
|
||||
regions.push(r.space, skol_var);
|
||||
}
|
||||
}
|
||||
|
||||
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
|
||||
types: &mut subst::VecPerParamSpace<ty::Ty<'tcx>>,
|
||||
defs: &[ty::TypeParameterDef<'tcx>]) {
|
||||
for def in defs {
|
||||
let ty = ty::mk_param_from_def(tcx, def);
|
||||
types.push(def.space, ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
|
||||
binder: &ty::Binder<T>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
|
|
|
@ -726,6 +726,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn construct_skolemized_subst(&self,
|
||||
generics: &ty::Generics<'tcx>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
-> (subst::Substs<'tcx>, SkolemizationMap) {
|
||||
/*! See `higher_ranked::construct_skolemized_subst` */
|
||||
|
||||
higher_ranked::construct_skolemized_substs(self, generics, snapshot)
|
||||
}
|
||||
|
||||
pub fn skolemize_late_bound_regions<T>(&self,
|
||||
value: &ty::Binder<T>,
|
||||
snapshot: &CombinedSnapshot)
|
||||
|
|
|
@ -789,10 +789,13 @@ fn confirm_callable_candidate<'cx,'tcx>(
|
|||
obligation.repr(tcx),
|
||||
fn_sig.repr(tcx));
|
||||
|
||||
// the `Output` associated type is declared on `FnOnce`
|
||||
let fn_once_def_id = tcx.lang_items.fn_once_trait().unwrap();
|
||||
|
||||
// Note: we unwrap the binder here but re-create it below (1)
|
||||
let ty::Binder((trait_ref, ret_type)) =
|
||||
util::closure_trait_ref_and_return_type(tcx,
|
||||
obligation.predicate.trait_ref.def_id,
|
||||
fn_once_def_id,
|
||||
obligation.predicate.trait_ref.self_ty(),
|
||||
fn_sig,
|
||||
flag);
|
||||
|
|
|
@ -1069,7 +1069,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
match self.closure_typer.closure_kind(closure_def_id) {
|
||||
Some(closure_kind) => {
|
||||
debug!("assemble_unboxed_candidates: closure_kind = {:?}", closure_kind);
|
||||
if closure_kind == kind {
|
||||
if closure_kind.extends(kind) {
|
||||
candidates.vec.push(ClosureCandidate(closure_def_id, substs.clone()));
|
||||
}
|
||||
}
|
||||
|
@ -1088,10 +1088,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
candidates: &mut SelectionCandidateSet<'tcx>)
|
||||
-> Result<(),SelectionError<'tcx>>
|
||||
{
|
||||
// We provide a `Fn` impl for fn pointers. There is no need to provide
|
||||
// the other traits (e.g. `FnMut`) since those are provided by blanket
|
||||
// impls.
|
||||
if Some(obligation.predicate.def_id()) != self.tcx().lang_items.fn_trait() {
|
||||
// We provide impl of all fn traits for fn pointers.
|
||||
if self.tcx().lang_items.fn_trait_kind(obligation.predicate.def_id()).is_none() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
|
|
@ -968,7 +968,7 @@ impl<'tcx> Eq for TyS<'tcx> {}
|
|||
|
||||
impl<'tcx> Hash for TyS<'tcx> {
|
||||
fn hash<H: Hasher>(&self, s: &mut H) {
|
||||
(self as *const _).hash(s)
|
||||
(self as *const TyS).hash(s)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1793,6 +1793,9 @@ impl RegionParameterDef {
|
|||
pub fn to_early_bound_region(&self) -> ty::Region {
|
||||
ty::ReEarlyBound(self.def_id.node, self.space, self.index, self.name)
|
||||
}
|
||||
pub fn to_bound_region(&self) -> ty::BoundRegion {
|
||||
ty::BoundRegion::BrNamed(self.def_id, self.name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about the formal type/lifetime parameters associated
|
||||
|
@ -2462,8 +2465,11 @@ pub struct ItemSubsts<'tcx> {
|
|||
pub substs: Substs<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
|
||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub enum ClosureKind {
|
||||
// Warning: Ordering is significant here! The ordering is chosen
|
||||
// because the trait Fn is a subtrait of FnMut and so in turn, and
|
||||
// hence we order it so that Fn < FnMut < FnOnce.
|
||||
FnClosureKind,
|
||||
FnMutClosureKind,
|
||||
FnOnceClosureKind,
|
||||
|
@ -2485,6 +2491,20 @@ impl ClosureKind {
|
|||
Err(err) => cx.sess.fatal(&err[..]),
|
||||
}
|
||||
}
|
||||
|
||||
/// True if this a type that impls this closure kind
|
||||
/// must also implement `other`.
|
||||
pub fn extends(self, other: ty::ClosureKind) -> bool {
|
||||
match (self, other) {
|
||||
(FnClosureKind, FnClosureKind) => true,
|
||||
(FnClosureKind, FnMutClosureKind) => true,
|
||||
(FnClosureKind, FnOnceClosureKind) => true,
|
||||
(FnMutClosureKind, FnMutClosureKind) => true,
|
||||
(FnMutClosureKind, FnOnceClosureKind) => true,
|
||||
(FnOnceClosureKind, FnOnceClosureKind) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ClosureTyper<'tcx> {
|
||||
|
@ -2721,7 +2741,7 @@ fn intern_ty<'tcx>(type_arena: &'tcx TypedArena<TyS<'tcx>>,
|
|||
};
|
||||
|
||||
debug!("Interned type: {:?} Pointer: {:?}",
|
||||
ty, ty as *const _);
|
||||
ty, ty as *const TyS);
|
||||
|
||||
interner.insert(InternedTy { ty: ty }, ty);
|
||||
|
||||
|
@ -4806,32 +4826,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
|||
RvalueDpsExpr
|
||||
}
|
||||
|
||||
ast::ExprCast(..) => {
|
||||
match tcx.node_types.borrow().get(&expr.id) {
|
||||
Some(&ty) => {
|
||||
if type_is_trait(ty) {
|
||||
RvalueDpsExpr
|
||||
} else {
|
||||
RvalueDatumExpr
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// Technically, it should not happen that the expr is not
|
||||
// present within the table. However, it DOES happen
|
||||
// during type check, because the final types from the
|
||||
// expressions are not yet recorded in the tcx. At that
|
||||
// time, though, we are only interested in knowing lvalue
|
||||
// vs rvalue. It would be better to base this decision on
|
||||
// the AST type in cast node---but (at the time of this
|
||||
// writing) it's not easy to distinguish casts to traits
|
||||
// from other casts based on the AST. This should be
|
||||
// easier in the future, when casts to traits
|
||||
// would like @Foo, Box<Foo>, or &Foo.
|
||||
RvalueDatumExpr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ast::ExprBreak(..) |
|
||||
ast::ExprAgain(..) |
|
||||
ast::ExprRet(..) |
|
||||
|
@ -4847,7 +4841,8 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
|||
ast::ExprUnary(..) |
|
||||
ast::ExprBox(None, _) |
|
||||
ast::ExprAddrOf(..) |
|
||||
ast::ExprBinary(..) => {
|
||||
ast::ExprBinary(..) |
|
||||
ast::ExprCast(..) => {
|
||||
RvalueDatumExpr
|
||||
}
|
||||
|
||||
|
|
|
@ -84,30 +84,6 @@ impl LintPass for WhileTrue {
|
|||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
UNUSED_TYPECASTS,
|
||||
Allow,
|
||||
"detects unnecessary type casts that can be removed"
|
||||
}
|
||||
|
||||
#[derive(Copy)]
|
||||
pub struct UnusedCasts;
|
||||
|
||||
impl LintPass for UnusedCasts {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(UNUSED_TYPECASTS)
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||
if let ast::ExprCast(ref expr, ref ty) = e.node {
|
||||
let t_t = ty::expr_ty(cx.tcx, e);
|
||||
if ty::expr_ty(cx.tcx, &**expr) == t_t {
|
||||
cx.span_lint(UNUSED_TYPECASTS, ty.span, "unnecessary type cast");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare_lint! {
|
||||
UNSIGNED_NEGATION,
|
||||
Warn,
|
||||
|
@ -1804,6 +1780,9 @@ impl LintPass for UnconditionalRecursion {
|
|||
|
||||
fn check_fn(&mut self, cx: &Context, fn_kind: visit::FnKind, _: &ast::FnDecl,
|
||||
blk: &ast::Block, sp: Span, id: ast::NodeId) {
|
||||
// FIXME(#23542) Replace with type ascription.
|
||||
#![allow(trivial_casts)]
|
||||
|
||||
type F = for<'tcx> fn(&ty::ctxt<'tcx>,
|
||||
ast::NodeId, ast::NodeId, ast::Ident, ast::NodeId) -> bool;
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ pub use rustc::session as session;
|
|||
pub use rustc::util as util;
|
||||
|
||||
use session::Session;
|
||||
use lint::{LintPassObject, LintId};
|
||||
use lint::LintId;
|
||||
|
||||
mod builtin;
|
||||
|
||||
|
@ -67,7 +67,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
macro_rules! add_builtin {
|
||||
($sess:ident, $($name:ident),*,) => (
|
||||
{$(
|
||||
store.register_pass($sess, false, box builtin::$name as LintPassObject);
|
||||
store.register_pass($sess, false, box builtin::$name);
|
||||
)*}
|
||||
)
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
macro_rules! add_builtin_with_new {
|
||||
($sess:ident, $($name:ident),*,) => (
|
||||
{$(
|
||||
store.register_pass($sess, false, box builtin::$name::new() as LintPassObject);
|
||||
store.register_pass($sess, false, box builtin::$name::new());
|
||||
)*}
|
||||
)
|
||||
}
|
||||
|
@ -89,7 +89,6 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
add_builtin!(sess,
|
||||
HardwiredLints,
|
||||
WhileTrue,
|
||||
UnusedCasts,
|
||||
ImproperCTypes,
|
||||
BoxPointers,
|
||||
UnusedAttributes,
|
||||
|
@ -129,7 +128,7 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
|
|||
UNUSED_UNSAFE, PATH_STATEMENTS);
|
||||
|
||||
// We have one lint pass defined specially
|
||||
store.register_pass(sess, false, box lint::GatherNodeLevels as LintPassObject);
|
||||
store.register_pass(sess, false, box lint::GatherNodeLevels);
|
||||
|
||||
// Insert temporary renamings for a one-time deprecation
|
||||
store.register_renamed("raw_pointer_deriving", "raw_pointer_derive");
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
#![crate_name = "rustc_llvm"]
|
||||
#![unstable(feature = "rustc_private")]
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
#![feature(convert)]
|
||||
#![feature(path_relative_from)]
|
||||
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
extern crate arena;
|
||||
extern crate flate;
|
||||
extern crate getopts;
|
||||
|
|
|
@ -264,14 +264,29 @@ fn trans_fn_ref_with_substs_to_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
/// but for the bare function type given.
|
||||
pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
||||
ccx: &'a CrateContext<'a, 'tcx>,
|
||||
closure_kind: ty::ClosureKind,
|
||||
bare_fn_ty: Ty<'tcx>)
|
||||
-> ValueRef
|
||||
{
|
||||
let _icx = push_ctxt("trans_fn_pointer_shim");
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
// Normalize the type for better caching.
|
||||
let bare_fn_ty = common::erase_regions(tcx, &bare_fn_ty);
|
||||
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty) {
|
||||
|
||||
// If this is an impl of `Fn` or `FnMut` trait, the receiver is `&self`.
|
||||
let is_by_ref = match closure_kind {
|
||||
ty::FnClosureKind | ty::FnMutClosureKind => true,
|
||||
ty::FnOnceClosureKind => false,
|
||||
};
|
||||
let bare_fn_ty_maybe_ref = if is_by_ref {
|
||||
ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty)
|
||||
} else {
|
||||
bare_fn_ty
|
||||
};
|
||||
|
||||
// Check if we already trans'd this shim.
|
||||
match ccx.fn_pointer_shims().borrow().get(&bare_fn_ty_maybe_ref) {
|
||||
Some(&llval) => { return llval; }
|
||||
None => { }
|
||||
}
|
||||
|
@ -279,9 +294,6 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
|||
debug!("trans_fn_pointer_shim(bare_fn_ty={})",
|
||||
bare_fn_ty.repr(tcx));
|
||||
|
||||
// This is an impl of `Fn` trait, so receiver is `&self`.
|
||||
let bare_fn_ty_ref = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), bare_fn_ty);
|
||||
|
||||
// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
|
||||
// which is the fn pointer, and `args`, which is the arguments tuple.
|
||||
let (opt_def_id, sig) =
|
||||
|
@ -306,7 +318,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
|||
unsafety: ast::Unsafety::Normal,
|
||||
abi: synabi::RustCall,
|
||||
sig: ty::Binder(ty::FnSig {
|
||||
inputs: vec![bare_fn_ty_ref,
|
||||
inputs: vec![bare_fn_ty_maybe_ref,
|
||||
tuple_input_ty],
|
||||
output: sig.output,
|
||||
variadic: false
|
||||
|
@ -337,8 +349,11 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
|||
let mut bcx = init_function(&fcx, false, sig.output);
|
||||
|
||||
// the first argument (`self`) will be ptr to the the fn pointer
|
||||
let llfnpointer =
|
||||
Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32));
|
||||
let llfnpointer = if is_by_ref {
|
||||
Load(bcx, get_param(fcx.llfn, fcx.arg_pos(0) as u32))
|
||||
} else {
|
||||
get_param(fcx.llfn, fcx.arg_pos(0) as u32)
|
||||
};
|
||||
|
||||
// the remaining arguments will be the untupled values
|
||||
let llargs: Vec<_> =
|
||||
|
@ -361,7 +376,7 @@ pub fn trans_fn_pointer_shim<'a, 'tcx>(
|
|||
|
||||
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
|
||||
|
||||
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty, llfn);
|
||||
ccx.fn_pointer_shims().borrow_mut().insert(bare_fn_ty_maybe_ref, llfn);
|
||||
|
||||
llfn
|
||||
}
|
||||
|
|
|
@ -8,24 +8,27 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use back::link::mangle_internal_name_by_path_and_seq;
|
||||
use llvm::ValueRef;
|
||||
use arena::TypedArena;
|
||||
use back::link::{self, mangle_internal_name_by_path_and_seq};
|
||||
use llvm::{ValueRef, get_param};
|
||||
use middle::mem_categorization::Typer;
|
||||
use trans::adt;
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
use trans::cleanup::{CleanupMethods, ScopeId};
|
||||
use trans::callee::{self, ArgVals, Callee, TraitItem, MethodData};
|
||||
use trans::cleanup::{CleanupMethods, CustomScope, ScopeId};
|
||||
use trans::common::*;
|
||||
use trans::datum::{Datum, rvalue_scratch_datum};
|
||||
use trans::datum::{Rvalue, ByValue};
|
||||
use trans::debuginfo;
|
||||
use trans::datum::{self, Datum, rvalue_scratch_datum, Rvalue, ByValue};
|
||||
use trans::debuginfo::{self, DebugLoc};
|
||||
use trans::expr;
|
||||
use trans::monomorphize::{self, MonoId};
|
||||
use trans::type_of::*;
|
||||
use middle::ty::{self, ClosureTyper};
|
||||
use middle::subst::{Substs};
|
||||
use session::config::FullDebugInfo;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::abi::RustCall;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
|
||||
|
@ -239,11 +242,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
|||
// Create the closure.
|
||||
for (i, freevar) in freevars.iter().enumerate() {
|
||||
let datum = expr::trans_local_var(bcx, freevar.def);
|
||||
let upvar_slot_dest = adt::trans_field_ptr(bcx,
|
||||
&*repr,
|
||||
dest_addr,
|
||||
0,
|
||||
i);
|
||||
let upvar_slot_dest = adt::trans_field_ptr(bcx, &*repr, dest_addr, 0, i);
|
||||
let upvar_id = ty::UpvarId { var_id: freevar.def.local_node_id(),
|
||||
closure_expr_id: id };
|
||||
match tcx.upvar_capture(upvar_id).unwrap() {
|
||||
|
@ -259,3 +258,186 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
|
|||
|
||||
Some(bcx)
|
||||
}
|
||||
|
||||
pub fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
|
||||
closure_def_id: ast::DefId,
|
||||
substs: Substs<'tcx>,
|
||||
node: ExprOrMethodCall,
|
||||
param_substs: &'tcx Substs<'tcx>,
|
||||
trait_closure_kind: ty::ClosureKind)
|
||||
-> ValueRef
|
||||
{
|
||||
// The substitutions should have no type parameters remaining
|
||||
// after passing through fulfill_obligation
|
||||
let llfn = callee::trans_fn_ref_with_substs(ccx,
|
||||
closure_def_id,
|
||||
node,
|
||||
param_substs,
|
||||
substs.clone()).val;
|
||||
|
||||
// If the closure is a Fn closure, but a FnOnce is needed (etc),
|
||||
// then adapt the self type
|
||||
let closure_kind = ccx.tcx().closure_kind(closure_def_id);
|
||||
trans_closure_adapter_shim(ccx,
|
||||
closure_def_id,
|
||||
substs,
|
||||
closure_kind,
|
||||
trait_closure_kind,
|
||||
llfn)
|
||||
}
|
||||
|
||||
fn trans_closure_adapter_shim<'a, 'tcx>(
|
||||
ccx: &'a CrateContext<'a, 'tcx>,
|
||||
closure_def_id: ast::DefId,
|
||||
substs: Substs<'tcx>,
|
||||
llfn_closure_kind: ty::ClosureKind,
|
||||
trait_closure_kind: ty::ClosureKind,
|
||||
llfn: ValueRef)
|
||||
-> ValueRef
|
||||
{
|
||||
let _icx = push_ctxt("trans_closure_adapter_shim");
|
||||
let tcx = ccx.tcx();
|
||||
|
||||
debug!("trans_closure_adapter_shim(llfn_closure_kind={:?}, \
|
||||
trait_closure_kind={:?}, \
|
||||
llfn={})",
|
||||
llfn_closure_kind,
|
||||
trait_closure_kind,
|
||||
ccx.tn().val_to_string(llfn));
|
||||
|
||||
match (llfn_closure_kind, trait_closure_kind) {
|
||||
(ty::FnClosureKind, ty::FnClosureKind) |
|
||||
(ty::FnMutClosureKind, ty::FnMutClosureKind) |
|
||||
(ty::FnOnceClosureKind, ty::FnOnceClosureKind) => {
|
||||
// No adapter needed.
|
||||
llfn
|
||||
}
|
||||
(ty::FnClosureKind, ty::FnMutClosureKind) => {
|
||||
// The closure fn `llfn` is a `fn(&self, ...)`. We want a
|
||||
// `fn(&mut self, ...)`. In fact, at trans time, these are
|
||||
// basically the same thing, so we can just return llfn.
|
||||
llfn
|
||||
}
|
||||
(ty::FnClosureKind, ty::FnOnceClosureKind) |
|
||||
(ty::FnMutClosureKind, ty::FnOnceClosureKind) => {
|
||||
// The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
|
||||
// self, ...)`. We want a `fn(self, ...)`. We can produce
|
||||
// this by doing something like:
|
||||
//
|
||||
// fn call_once(self, ...) { call_mut(&self, ...) }
|
||||
// fn call_once(mut self, ...) { call_mut(&mut self, ...) }
|
||||
//
|
||||
// These are both the same at trans time.
|
||||
trans_fn_once_adapter_shim(ccx, closure_def_id, substs, llfn)
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.bug(&format!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
|
||||
llfn_closure_kind,
|
||||
trait_closure_kind));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn trans_fn_once_adapter_shim<'a, 'tcx>(
|
||||
ccx: &'a CrateContext<'a, 'tcx>,
|
||||
closure_def_id: ast::DefId,
|
||||
substs: Substs<'tcx>,
|
||||
llreffn: ValueRef)
|
||||
-> ValueRef
|
||||
{
|
||||
debug!("trans_fn_once_adapter_shim(closure_def_id={}, substs={}, llreffn={})",
|
||||
closure_def_id.repr(ccx.tcx()),
|
||||
substs.repr(ccx.tcx()),
|
||||
ccx.tn().val_to_string(llreffn));
|
||||
|
||||
let tcx = ccx.tcx();
|
||||
let typer = NormalizingClosureTyper::new(tcx);
|
||||
|
||||
// Find a version of the closure type. Substitute static for the
|
||||
// region since it doesn't really matter.
|
||||
let substs = tcx.mk_substs(substs);
|
||||
let closure_ty = ty::mk_closure(tcx, closure_def_id, substs);
|
||||
let ref_closure_ty = ty::mk_imm_rptr(tcx, tcx.mk_region(ty::ReStatic), closure_ty);
|
||||
|
||||
// Make a version with the type of by-ref closure.
|
||||
let ty::ClosureTy { unsafety, abi, mut sig } = typer.closure_type(closure_def_id, substs);
|
||||
sig.0.inputs.insert(0, ref_closure_ty); // sig has no self type as of yet
|
||||
let llref_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety,
|
||||
abi: abi,
|
||||
sig: sig.clone() });
|
||||
let llref_fn_ty = ty::mk_bare_fn(tcx, None, llref_bare_fn_ty);
|
||||
debug!("trans_fn_once_adapter_shim: llref_fn_ty={}",
|
||||
llref_fn_ty.repr(tcx));
|
||||
|
||||
// Make a version of the closure type with the same arguments, but
|
||||
// with argument #0 being by value.
|
||||
assert_eq!(abi, RustCall);
|
||||
sig.0.inputs[0] = closure_ty;
|
||||
let llonce_bare_fn_ty = tcx.mk_bare_fn(ty::BareFnTy { unsafety: unsafety,
|
||||
abi: abi,
|
||||
sig: sig });
|
||||
let llonce_fn_ty = ty::mk_bare_fn(tcx, None, llonce_bare_fn_ty);
|
||||
|
||||
// Create the by-value helper.
|
||||
let function_name = link::mangle_internal_name_by_type_and_seq(ccx, llonce_fn_ty, "once_shim");
|
||||
let lloncefn = decl_internal_rust_fn(ccx, llonce_fn_ty, &function_name);
|
||||
|
||||
let sig = ty::erase_late_bound_regions(tcx, &llonce_bare_fn_ty.sig);
|
||||
let (block_arena, fcx): (TypedArena<_>, FunctionContext);
|
||||
block_arena = TypedArena::new();
|
||||
fcx = new_fn_ctxt(ccx,
|
||||
lloncefn,
|
||||
ast::DUMMY_NODE_ID,
|
||||
false,
|
||||
sig.output,
|
||||
substs,
|
||||
None,
|
||||
&block_arena);
|
||||
let mut bcx = init_function(&fcx, false, sig.output);
|
||||
|
||||
// the first argument (`self`) will be the (by value) closure env.
|
||||
let self_scope = fcx.push_custom_cleanup_scope();
|
||||
let self_scope_id = CustomScope(self_scope);
|
||||
let rvalue_mode = datum::appropriate_rvalue_mode(ccx, closure_ty);
|
||||
let llself = get_param(lloncefn, fcx.arg_pos(0) as u32);
|
||||
let env_datum = Datum::new(llself, closure_ty, Rvalue::new(rvalue_mode));
|
||||
let env_datum = unpack_datum!(bcx,
|
||||
env_datum.to_lvalue_datum_in_scope(bcx, "self",
|
||||
self_scope_id));
|
||||
|
||||
debug!("trans_fn_once_adapter_shim: env_datum={}",
|
||||
bcx.val_to_string(env_datum.val));
|
||||
|
||||
// the remaining arguments will be packed up in a tuple.
|
||||
let input_tys = match sig.inputs[1].sty {
|
||||
ty::ty_tup(ref tys) => &**tys,
|
||||
_ => bcx.sess().bug(&format!("trans_fn_once_adapter_shim: not rust-call! \
|
||||
closure_def_id={}",
|
||||
closure_def_id.repr(tcx)))
|
||||
};
|
||||
let llargs: Vec<_> =
|
||||
input_tys.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| get_param(lloncefn, fcx.arg_pos(i+1) as u32))
|
||||
.collect();
|
||||
|
||||
let dest =
|
||||
fcx.llretslotptr.get().map(
|
||||
|_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
|
||||
|
||||
let callee_data = TraitItem(MethodData { llfn: llreffn,
|
||||
llself: env_datum.val });
|
||||
|
||||
bcx = callee::trans_call_inner(bcx,
|
||||
DebugLoc::None,
|
||||
llref_fn_ty,
|
||||
|bcx, _| Callee { bcx: bcx, data: callee_data },
|
||||
ArgVals(&llargs),
|
||||
dest).bcx;
|
||||
|
||||
fcx.pop_custom_cleanup_scope(self_scope);
|
||||
|
||||
finish_fn(&fcx, bcx, sig.output, DebugLoc::None);
|
||||
|
||||
lloncefn
|
||||
}
|
||||
|
|
|
@ -471,15 +471,6 @@ impl<'tcx> Datum<'tcx, Expr> {
|
|||
})
|
||||
}
|
||||
|
||||
/// Ensures that `self` will get cleaned up, if it is not an lvalue already.
|
||||
pub fn clean<'blk>(self,
|
||||
bcx: Block<'blk, 'tcx>,
|
||||
name: &'static str,
|
||||
expr_id: ast::NodeId)
|
||||
-> Block<'blk, 'tcx> {
|
||||
self.to_lvalue_datum(bcx, name, expr_id).bcx
|
||||
}
|
||||
|
||||
pub fn to_lvalue_datum<'blk>(self,
|
||||
bcx: Block<'blk, 'tcx>,
|
||||
name: &str,
|
||||
|
|
|
@ -1227,22 +1227,9 @@ fn trans_rvalue_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
trans_overloaded_op(bcx, expr, MethodCall::expr(expr.id), base,
|
||||
vec![(idx_datum, idx.id)], Some(dest), true).bcx
|
||||
}
|
||||
ast::ExprCast(ref val, _) => {
|
||||
// DPS output mode means this is a trait cast:
|
||||
if ty::type_is_trait(node_id_type(bcx, expr.id)) {
|
||||
let trait_ref =
|
||||
bcx.tcx().object_cast_map.borrow()
|
||||
.get(&expr.id)
|
||||
.cloned()
|
||||
.unwrap();
|
||||
let trait_ref = bcx.monomorphize(&trait_ref);
|
||||
let datum = unpack_datum!(bcx, trans(bcx, &**val));
|
||||
meth::trans_trait_cast(bcx, datum, expr.id,
|
||||
trait_ref, dest)
|
||||
} else {
|
||||
bcx.tcx().sess.span_bug(expr.span,
|
||||
"expr_cast of non-trait");
|
||||
}
|
||||
ast::ExprCast(..) => {
|
||||
// Trait casts used to come this way, now they should be coercions.
|
||||
bcx.tcx().sess.span_bug(expr.span, "DPS expr_cast (residual trait cast?)")
|
||||
}
|
||||
ast::ExprAssignOp(op, ref dst, ref src) => {
|
||||
trans_assign_op(bcx, expr, op, &**dst, &**src)
|
||||
|
@ -2091,7 +2078,7 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
let mut bcx = bcx;
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
let t_in = expr_ty(bcx, expr);
|
||||
let t_in = expr_ty_adjusted(bcx, expr);
|
||||
let t_out = node_id_type(bcx, id);
|
||||
let k_in = cast_type_kind(bcx.tcx(), t_in);
|
||||
let k_out = cast_type_kind(bcx.tcx(), t_out);
|
||||
|
@ -2103,7 +2090,8 @@ fn trans_imm_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
// by-value as appropriate given its type:
|
||||
let mut datum = unpack_datum!(bcx, trans(bcx, expr));
|
||||
|
||||
if cast_is_noop(datum.ty, t_out) {
|
||||
let datum_ty = monomorphize_type(bcx, datum.ty);
|
||||
if cast_is_noop(datum_ty, t_out) {
|
||||
datum.ty = t_out;
|
||||
return DatumBlock::new(bcx, datum);
|
||||
}
|
||||
|
|
|
@ -17,16 +17,18 @@ use middle::subst::Substs;
|
|||
use middle::subst::VecPerParamSpace;
|
||||
use middle::subst;
|
||||
use middle::traits;
|
||||
use middle::ty::ClosureTyper;
|
||||
use trans::base::*;
|
||||
use trans::build::*;
|
||||
use trans::callee::*;
|
||||
use trans::callee;
|
||||
use trans::cleanup;
|
||||
use trans::closure;
|
||||
use trans::common::*;
|
||||
use trans::consts;
|
||||
use trans::datum::*;
|
||||
use trans::debuginfo::DebugLoc;
|
||||
use trans::expr::{SaveIn, Ignore};
|
||||
use trans::expr::SaveIn;
|
||||
use trans::expr;
|
||||
use trans::glue;
|
||||
use trans::machine;
|
||||
|
@ -358,19 +360,21 @@ fn trans_monomorphized_callee<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
|||
traits::VtableClosure(closure_def_id, substs) => {
|
||||
// The substitutions should have no type parameters remaining
|
||||
// after passing through fulfill_obligation
|
||||
let llfn = trans_fn_ref_with_substs(bcx.ccx(),
|
||||
closure_def_id,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs,
|
||||
substs).val;
|
||||
|
||||
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = closure::trans_closure_method(bcx.ccx(),
|
||||
closure_def_id,
|
||||
substs,
|
||||
MethodCallKey(method_call),
|
||||
bcx.fcx.param_substs,
|
||||
trait_closure_kind);
|
||||
Callee {
|
||||
bcx: bcx,
|
||||
data: Fn(llfn),
|
||||
}
|
||||
}
|
||||
traits::VtableFnPointer(fn_ty) => {
|
||||
let llfn = trans_fn_pointer_shim(bcx.ccx(), fn_ty);
|
||||
let trait_closure_kind = bcx.tcx().lang_items.fn_trait_kind(trait_id).unwrap();
|
||||
let llfn = trans_fn_pointer_shim(bcx.ccx(), trait_closure_kind, fn_ty);
|
||||
Callee { bcx: bcx, data: Fn(llfn) }
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
|
@ -645,9 +649,6 @@ pub fn trans_object_shim<'a, 'tcx>(
|
|||
|
||||
assert!(!fcx.needs_ret_allocas);
|
||||
|
||||
let sig =
|
||||
ty::erase_late_bound_regions(bcx.tcx(), &fty.sig);
|
||||
|
||||
let dest =
|
||||
fcx.llretslotptr.get().map(
|
||||
|_| expr::SaveIn(fcx.get_ret_slot(bcx, sig.output, "ret_slot")));
|
||||
|
@ -714,17 +715,18 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
emit_vtable_methods(ccx, id, substs, param_substs).into_iter()
|
||||
}
|
||||
traits::VtableClosure(closure_def_id, substs) => {
|
||||
let llfn = trans_fn_ref_with_substs(
|
||||
ccx,
|
||||
closure_def_id,
|
||||
ExprId(0),
|
||||
param_substs,
|
||||
substs).val;
|
||||
|
||||
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
|
||||
let llfn = closure::trans_closure_method(ccx,
|
||||
closure_def_id,
|
||||
substs,
|
||||
ExprId(0),
|
||||
param_substs,
|
||||
trait_closure_kind);
|
||||
vec![llfn].into_iter()
|
||||
}
|
||||
traits::VtableFnPointer(bare_fn_ty) => {
|
||||
vec![trans_fn_pointer_shim(ccx, bare_fn_ty)].into_iter()
|
||||
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_ref.def_id()).unwrap();
|
||||
vec![trans_fn_pointer_shim(ccx, trait_closure_kind, bare_fn_ty)].into_iter()
|
||||
}
|
||||
traits::VtableObject(ref data) => {
|
||||
// this would imply that the Self type being erased is
|
||||
|
@ -861,44 +863,6 @@ fn emit_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Generates the code to convert from a pointer (`Box<T>`, `&T`, etc) into an object
|
||||
/// (`Box<Trait>`, `&Trait`, etc). This means creating a pair where the first word is the vtable
|
||||
/// and the second word is the pointer.
|
||||
pub fn trans_trait_cast<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
datum: Datum<'tcx, Expr>,
|
||||
id: ast::NodeId,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
dest: expr::Dest)
|
||||
-> Block<'blk, 'tcx> {
|
||||
let mut bcx = bcx;
|
||||
let _icx = push_ctxt("meth::trans_trait_cast");
|
||||
|
||||
let lldest = match dest {
|
||||
Ignore => {
|
||||
return datum.clean(bcx, "trait_trait_cast", id);
|
||||
}
|
||||
SaveIn(dest) => dest
|
||||
};
|
||||
|
||||
debug!("trans_trait_cast: trait_ref={}",
|
||||
trait_ref.repr(bcx.tcx()));
|
||||
|
||||
let llty = type_of(bcx.ccx(), datum.ty);
|
||||
|
||||
// Store the pointer into the first half of pair.
|
||||
let llboxdest = GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR]);
|
||||
let llboxdest = PointerCast(bcx, llboxdest, llty.ptr_to());
|
||||
bcx = datum.store_to(bcx, llboxdest);
|
||||
|
||||
// Store the vtable into the second half of pair.
|
||||
let vtable = get_vtable(bcx.ccx(), trait_ref, bcx.fcx.param_substs);
|
||||
let llvtabledest = GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA]);
|
||||
let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to());
|
||||
Store(bcx, vtable, llvtabledest);
|
||||
|
||||
bcx
|
||||
}
|
||||
|
||||
/// Replace the self type (&Self or Box<Self>) with an opaque pointer.
|
||||
pub fn opaque_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>, method_ty: &ty::BareFnTy<'tcx>)
|
||||
-> &'tcx ty::BareFnTy<'tcx> {
|
||||
|
|
|
@ -55,7 +55,7 @@ use middle::resolve_lifetime as rl;
|
|||
use middle::privacy::{AllPublic, LastMod};
|
||||
use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs};
|
||||
use middle::traits;
|
||||
use middle::ty::{self, RegionEscape, ToPolyTraitRef, Ty};
|
||||
use middle::ty::{self, RegionEscape, Ty};
|
||||
use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
|
||||
ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope};
|
||||
use util::common::{ErrorReported, FN_OUTPUT_NAME};
|
||||
|
@ -608,24 +608,16 @@ pub fn instantiate_poly_trait_ref<'tcx>(
|
|||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
let mut projections = Vec::new();
|
||||
|
||||
// The trait reference introduces a binding level here, so
|
||||
// we need to shift the `rscope`. It'd be nice if we could
|
||||
// do away with this rscope stuff and work this knowledge
|
||||
// into resolve_lifetimes, as we do with non-omitted
|
||||
// lifetimes. Oh well, not there yet.
|
||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
||||
|
||||
let trait_ref = instantiate_trait_ref(this, &shifted_rscope,
|
||||
&ast_trait_ref.trait_ref,
|
||||
None, self_ty, Some(&mut projections));
|
||||
|
||||
for projection in projections {
|
||||
poly_projections.push(ty::Binder(projection));
|
||||
}
|
||||
|
||||
ty::Binder(trait_ref)
|
||||
let trait_ref = &ast_trait_ref.trait_ref;
|
||||
let trait_def_id = trait_def_id(this, trait_ref);
|
||||
ast_path_to_poly_trait_ref(this,
|
||||
rscope,
|
||||
trait_ref.path.span,
|
||||
PathParamMode::Explicit,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_ref.path.segments.last().unwrap(),
|
||||
poly_projections)
|
||||
}
|
||||
|
||||
/// Instantiates the path for the given trait reference, assuming that it's
|
||||
|
@ -634,31 +626,27 @@ pub fn instantiate_poly_trait_ref<'tcx>(
|
|||
///
|
||||
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
|
||||
/// are disallowed. Otherwise, they are pushed onto the vector given.
|
||||
pub fn instantiate_trait_ref<'tcx>(
|
||||
pub fn instantiate_mono_trait_ref<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
trait_ref: &ast::TraitRef,
|
||||
impl_id: Option<ast::NodeId>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
||||
self_ty: Option<Ty<'tcx>>)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
{
|
||||
let trait_def_id = trait_def_id(this, trait_ref);
|
||||
ast_path_to_mono_trait_ref(this,
|
||||
rscope,
|
||||
trait_ref.path.span,
|
||||
PathParamMode::Explicit,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_ref.path.segments.last().unwrap())
|
||||
}
|
||||
|
||||
fn trait_def_id<'tcx>(this: &AstConv<'tcx>, trait_ref: &ast::TraitRef) -> ast::DefId {
|
||||
let path = &trait_ref.path;
|
||||
match ::lookup_full_def(this.tcx(), path.span, trait_ref.ref_id) {
|
||||
def::DefTrait(trait_def_id) => {
|
||||
let trait_ref = ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
path.span,
|
||||
PathParamMode::Explicit,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
path.segments.last().unwrap(),
|
||||
projections);
|
||||
if let Some(id) = impl_id {
|
||||
this.tcx().impl_trait_refs.borrow_mut().insert(id, trait_ref.clone());
|
||||
}
|
||||
trait_ref
|
||||
}
|
||||
def::DefTrait(trait_def_id) => trait_def_id,
|
||||
_ => {
|
||||
span_fatal!(this.tcx().sess, path.span, E0245, "`{}` is not a trait",
|
||||
path.user_string(this.tcx()));
|
||||
|
@ -676,24 +664,17 @@ fn object_path_to_poly_trait_ref<'a,'tcx>(
|
|||
mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
// we are introducing a binder here, so shift the
|
||||
// anonymous regions depth to account for that
|
||||
let shifted_rscope = ShiftedRscope::new(rscope);
|
||||
|
||||
let mut tmp = Vec::new();
|
||||
let trait_ref = ty::Binder(ast_path_to_trait_ref(this,
|
||||
&shifted_rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
None,
|
||||
trait_segment,
|
||||
Some(&mut tmp)));
|
||||
projections.extend(tmp.into_iter().map(ty::Binder));
|
||||
trait_ref
|
||||
ast_path_to_poly_trait_ref(this,
|
||||
rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
None,
|
||||
trait_segment,
|
||||
projections)
|
||||
}
|
||||
|
||||
fn ast_path_to_trait_ref<'a,'tcx>(
|
||||
fn ast_path_to_poly_trait_ref<'a,'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
|
@ -701,10 +682,78 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
|||
trait_def_id: ast::DefId,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
trait_segment: &ast::PathSegment,
|
||||
mut projections: Option<&mut Vec<ty::ProjectionPredicate<'tcx>>>)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
|
||||
-> ty::PolyTraitRef<'tcx>
|
||||
{
|
||||
debug!("ast_path_to_trait_ref {:?}", trait_segment);
|
||||
// The trait reference introduces a binding level here, so
|
||||
// we need to shift the `rscope`. It'd be nice if we could
|
||||
// do away with this rscope stuff and work this knowledge
|
||||
// into resolve_lifetimes, as we do with non-omitted
|
||||
// lifetimes. Oh well, not there yet.
|
||||
let shifted_rscope = &ShiftedRscope::new(rscope);
|
||||
|
||||
let (substs, assoc_bindings) =
|
||||
create_substs_for_ast_trait_ref(this,
|
||||
shifted_rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_segment);
|
||||
let poly_trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_def_id, substs)));
|
||||
|
||||
{
|
||||
let converted_bindings =
|
||||
assoc_bindings
|
||||
.iter()
|
||||
.filter_map(|binding| {
|
||||
// specify type to assert that error was already reported in Err case:
|
||||
let predicate: Result<_, ErrorReported> =
|
||||
ast_type_binding_to_poly_projection_predicate(this,
|
||||
poly_trait_ref.clone(),
|
||||
self_ty,
|
||||
binding);
|
||||
predicate.ok() // ok to ignore Err() because ErrorReported (see above)
|
||||
});
|
||||
poly_projections.extend(converted_bindings);
|
||||
}
|
||||
|
||||
poly_trait_ref
|
||||
}
|
||||
|
||||
fn ast_path_to_mono_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
param_mode: PathParamMode,
|
||||
trait_def_id: ast::DefId,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
trait_segment: &ast::PathSegment)
|
||||
-> Rc<ty::TraitRef<'tcx>>
|
||||
{
|
||||
let (substs, assoc_bindings) =
|
||||
create_substs_for_ast_trait_ref(this,
|
||||
rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
self_ty,
|
||||
trait_segment);
|
||||
prohibit_projections(this.tcx(), &assoc_bindings);
|
||||
Rc::new(ty::TraitRef::new(trait_def_id, substs))
|
||||
}
|
||||
|
||||
fn create_substs_for_ast_trait_ref<'a,'tcx>(this: &AstConv<'tcx>,
|
||||
rscope: &RegionScope,
|
||||
span: Span,
|
||||
param_mode: PathParamMode,
|
||||
trait_def_id: ast::DefId,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
trait_segment: &ast::PathSegment)
|
||||
-> (&'tcx Substs<'tcx>, Vec<ConvertedBinding<'tcx>>)
|
||||
{
|
||||
debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
|
||||
trait_segment);
|
||||
|
||||
let trait_def = match this.get_trait_def(span, trait_def_id) {
|
||||
Ok(trait_def) => trait_def,
|
||||
Err(ErrorReported) => {
|
||||
|
@ -752,34 +801,16 @@ fn ast_path_to_trait_ref<'a,'tcx>(
|
|||
self_ty,
|
||||
types,
|
||||
regions);
|
||||
let substs = this.tcx().mk_substs(substs);
|
||||
|
||||
let trait_ref = Rc::new(ty::TraitRef::new(trait_def_id, substs));
|
||||
|
||||
match projections {
|
||||
None => {
|
||||
prohibit_projections(this.tcx(), &assoc_bindings);
|
||||
}
|
||||
Some(ref mut v) => {
|
||||
for binding in &assoc_bindings {
|
||||
match ast_type_binding_to_projection_predicate(this, trait_ref.clone(),
|
||||
self_ty, binding) {
|
||||
Ok(pp) => { v.push(pp); }
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait_ref
|
||||
(this.tcx().mk_substs(substs), assoc_bindings)
|
||||
}
|
||||
|
||||
fn ast_type_binding_to_projection_predicate<'tcx>(
|
||||
fn ast_type_binding_to_poly_projection_predicate<'tcx>(
|
||||
this: &AstConv<'tcx>,
|
||||
mut trait_ref: Rc<ty::TraitRef<'tcx>>,
|
||||
mut trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
self_ty: Option<Ty<'tcx>>,
|
||||
binding: &ConvertedBinding<'tcx>)
|
||||
-> Result<ty::ProjectionPredicate<'tcx>, ErrorReported>
|
||||
-> Result<ty::PolyProjectionPredicate<'tcx>, ErrorReported>
|
||||
{
|
||||
let tcx = this.tcx();
|
||||
|
||||
|
@ -800,14 +831,14 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
|
|||
// We want to produce `<B as SuperTrait<int>>::T == foo`.
|
||||
|
||||
// Simple case: X is defined in the current trait.
|
||||
if this.trait_defines_associated_type_named(trait_ref.def_id, binding.item_name) {
|
||||
return Ok(ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
trait_ref: trait_ref,
|
||||
if this.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
|
||||
return Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------+
|
||||
projection_ty: ty::ProjectionTy { // |
|
||||
trait_ref: trait_ref.skip_binder().clone(), // Binder moved here --+
|
||||
item_name: binding.item_name,
|
||||
},
|
||||
ty: binding.ty,
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
// Otherwise, we have to walk through the supertraits to find
|
||||
|
@ -820,17 +851,17 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
|
|||
|
||||
let dummy_self_ty = ty::mk_infer(tcx, ty::FreshTy(0));
|
||||
if self_ty.is_none() { // if converting for an object type
|
||||
let mut dummy_substs = trait_ref.substs.clone();
|
||||
assert!(dummy_substs.self_ty().is_none());
|
||||
dummy_substs.types.push(SelfSpace, dummy_self_ty);
|
||||
trait_ref = Rc::new(ty::TraitRef::new(trait_ref.def_id,
|
||||
tcx.mk_substs(dummy_substs)));
|
||||
let mut dummy_substs = trait_ref.skip_binder().substs.clone(); // binder moved here -+
|
||||
assert!(dummy_substs.self_ty().is_none()); // |
|
||||
dummy_substs.types.push(SelfSpace, dummy_self_ty); // |
|
||||
trait_ref = ty::Binder(Rc::new(ty::TraitRef::new(trait_ref.def_id(), // <------------+
|
||||
tcx.mk_substs(dummy_substs))));
|
||||
}
|
||||
|
||||
try!(this.ensure_super_predicates(binding.span, trait_ref.def_id));
|
||||
try!(this.ensure_super_predicates(binding.span, trait_ref.def_id()));
|
||||
|
||||
let mut candidates: Vec<ty::PolyTraitRef> =
|
||||
traits::supertraits(tcx, trait_ref.to_poly_trait_ref())
|
||||
traits::supertraits(tcx, trait_ref.clone())
|
||||
.filter(|r| this.trait_defines_associated_type_named(r.def_id(), binding.item_name))
|
||||
.collect();
|
||||
|
||||
|
@ -865,21 +896,13 @@ fn ast_type_binding_to_projection_predicate<'tcx>(
|
|||
}
|
||||
};
|
||||
|
||||
if ty::binds_late_bound_regions(tcx, &candidate) {
|
||||
span_err!(tcx.sess, binding.span, E0219,
|
||||
"associated type `{}` defined in higher-ranked supertrait `{}`",
|
||||
token::get_name(binding.item_name),
|
||||
candidate.user_string(tcx));
|
||||
return Err(ErrorReported);
|
||||
}
|
||||
|
||||
Ok(ty::ProjectionPredicate {
|
||||
projection_ty: ty::ProjectionTy {
|
||||
trait_ref: candidate.0,
|
||||
Ok(ty::Binder(ty::ProjectionPredicate { // <-------------------------+
|
||||
projection_ty: ty::ProjectionTy { // |
|
||||
trait_ref: candidate.skip_binder().clone(), // binder is moved up here --+
|
||||
item_name: binding.item_name,
|
||||
},
|
||||
ty: binding.ty,
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
fn ast_path_to_ty<'tcx>(
|
||||
|
@ -1134,14 +1157,14 @@ fn qpath_to_ty<'tcx>(this: &AstConv<'tcx>,
|
|||
|
||||
debug!("qpath_to_ty: self_type={}", self_ty.repr(tcx));
|
||||
|
||||
let trait_ref = ast_path_to_trait_ref(this,
|
||||
rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
Some(self_ty),
|
||||
trait_segment,
|
||||
None);
|
||||
let trait_ref =
|
||||
ast_path_to_mono_trait_ref(this,
|
||||
rscope,
|
||||
span,
|
||||
param_mode,
|
||||
trait_def_id,
|
||||
Some(self_ty),
|
||||
trait_segment);
|
||||
|
||||
debug!("qpath_to_ty: trait_ref={}", trait_ref.repr(tcx));
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ use astconv;
|
|||
use middle::region;
|
||||
use middle::subst;
|
||||
use middle::ty::{self, ToPolyTraitRef, Ty};
|
||||
use std::cmp;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast_util;
|
||||
|
@ -109,15 +110,11 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
|
|||
ty::ty_trait(ref object_type) => {
|
||||
let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
|
||||
fcx.tcx().types.err);
|
||||
let expectations =
|
||||
proj_bounds.iter()
|
||||
.filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
|
||||
.next();
|
||||
|
||||
match expectations {
|
||||
Some((sig, kind)) => (Some(sig), Some(kind)),
|
||||
None => (None, None)
|
||||
}
|
||||
let sig = proj_bounds.iter()
|
||||
.filter_map(|pb| deduce_sig_from_projection(fcx, pb))
|
||||
.next();
|
||||
let kind = fcx.tcx().lang_items.fn_trait_kind(object_type.principal_def_id());
|
||||
(sig, kind)
|
||||
}
|
||||
ty::ty_infer(ty::TyVar(vid)) => {
|
||||
deduce_expectations_from_obligations(fcx, vid)
|
||||
|
@ -136,7 +133,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
|
|||
let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
|
||||
// Here `expected_ty` is known to be a type inference variable.
|
||||
|
||||
let expected_sig_and_kind =
|
||||
let expected_sig =
|
||||
fulfillment_cx
|
||||
.pending_obligations()
|
||||
.iter()
|
||||
|
@ -150,7 +147,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
|
|||
ty::Predicate::Projection(ref proj_predicate) => {
|
||||
let trait_ref = proj_predicate.to_poly_trait_ref();
|
||||
self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
|
||||
.and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate))
|
||||
.and_then(|_| deduce_sig_from_projection(fcx, proj_predicate))
|
||||
}
|
||||
_ => {
|
||||
None
|
||||
|
@ -159,14 +156,10 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
|
|||
})
|
||||
.next();
|
||||
|
||||
match expected_sig_and_kind {
|
||||
Some((sig, kind)) => { return (Some(sig), Some(kind)); }
|
||||
None => { }
|
||||
}
|
||||
|
||||
// Even if we can't infer the full signature, we may be able to
|
||||
// infer the kind. This can occur if there is a trait-reference
|
||||
// like `F : Fn<A>`.
|
||||
// like `F : Fn<A>`. Note that due to subtyping we could encounter
|
||||
// many viable options, so pick the most restrictive.
|
||||
let expected_kind =
|
||||
fulfillment_cx
|
||||
.pending_obligations()
|
||||
|
@ -183,54 +176,61 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
|
|||
.and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
|
||||
.and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
|
||||
})
|
||||
.next();
|
||||
.fold(None, pick_most_restrictive_closure_kind);
|
||||
|
||||
(None, expected_kind)
|
||||
(expected_sig, expected_kind)
|
||||
}
|
||||
|
||||
fn pick_most_restrictive_closure_kind(best: Option<ty::ClosureKind>,
|
||||
cur: ty::ClosureKind)
|
||||
-> Option<ty::ClosureKind>
|
||||
{
|
||||
match best {
|
||||
None => Some(cur),
|
||||
Some(best) => Some(cmp::min(best, cur))
|
||||
}
|
||||
}
|
||||
|
||||
/// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
|
||||
/// everything we need to know about a closure.
|
||||
fn deduce_expectations_from_projection<'a,'tcx>(
|
||||
fn deduce_sig_from_projection<'a,'tcx>(
|
||||
fcx: &FnCtxt<'a,'tcx>,
|
||||
projection: &ty::PolyProjectionPredicate<'tcx>)
|
||||
-> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
|
||||
-> Option<ty::FnSig<'tcx>>
|
||||
{
|
||||
let tcx = fcx.tcx();
|
||||
|
||||
debug!("deduce_expectations_from_projection({})",
|
||||
debug!("deduce_sig_from_projection({})",
|
||||
projection.repr(tcx));
|
||||
|
||||
let trait_ref = projection.to_poly_trait_ref();
|
||||
|
||||
let kind = match tcx.lang_items.fn_trait_kind(trait_ref.def_id()) {
|
||||
Some(k) => k,
|
||||
None => { return None; }
|
||||
};
|
||||
|
||||
debug!("found object type {:?}", kind);
|
||||
if tcx.lang_items.fn_trait_kind(trait_ref.def_id()).is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let arg_param_ty = *trait_ref.substs().types.get(subst::TypeSpace, 0);
|
||||
let arg_param_ty = fcx.infcx().resolve_type_vars_if_possible(&arg_param_ty);
|
||||
debug!("arg_param_ty {}", arg_param_ty.repr(tcx));
|
||||
debug!("deduce_sig_from_projection: arg_param_ty {}", arg_param_ty.repr(tcx));
|
||||
|
||||
let input_tys = match arg_param_ty.sty {
|
||||
ty::ty_tup(ref tys) => { (*tys).clone() }
|
||||
_ => { return None; }
|
||||
};
|
||||
debug!("input_tys {}", input_tys.repr(tcx));
|
||||
debug!("deduce_sig_from_projection: input_tys {}", input_tys.repr(tcx));
|
||||
|
||||
let ret_param_ty = projection.0.ty;
|
||||
let ret_param_ty = fcx.infcx().resolve_type_vars_if_possible(&ret_param_ty);
|
||||
debug!("ret_param_ty {}", ret_param_ty.repr(tcx));
|
||||
debug!("deduce_sig_from_projection: ret_param_ty {}", ret_param_ty.repr(tcx));
|
||||
|
||||
let fn_sig = ty::FnSig {
|
||||
inputs: input_tys,
|
||||
output: ty::FnConverging(ret_param_ty),
|
||||
variadic: false
|
||||
};
|
||||
debug!("fn_sig {}", fn_sig.repr(tcx));
|
||||
debug!("deduce_sig_from_projection: fn_sig {}", fn_sig.repr(tcx));
|
||||
|
||||
return Some((fn_sig, kind));
|
||||
Some(fn_sig)
|
||||
}
|
||||
|
||||
fn self_type_matches_expected_vid<'a,'tcx>(
|
||||
|
|
|
@ -258,70 +258,64 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
|
||||
match (&a.sty, &b.sty) {
|
||||
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_rptr(_, mt_b)) => {
|
||||
self.unpack_actual_value(t_a, |a| {
|
||||
match self.unsize_ty(t_a, a, mt_b.ty) {
|
||||
Some((ty, kind)) => {
|
||||
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
|
||||
return Err(ty::terr_mutability);
|
||||
}
|
||||
|
||||
let coercion = Coercion(self.trace.clone());
|
||||
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)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoPtr(AutoUnsize({:?})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
|
||||
Some(box AutoUnsize(kind))))
|
||||
})))
|
||||
match self.unsize_ty(t_a, mt_b.ty) {
|
||||
Some((ty, kind)) => {
|
||||
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
|
||||
return Err(ty::terr_mutability);
|
||||
}
|
||||
_ => Err(ty::terr_mismatch)
|
||||
|
||||
let coercion = Coercion(self.trace.clone());
|
||||
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)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoPtr(AutoUnsize({:?})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoPtr(r_borrow, mt_b.mutbl,
|
||||
Some(box AutoUnsize(kind))))
|
||||
})))
|
||||
}
|
||||
})
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
}
|
||||
(&ty::ty_rptr(_, ty::mt{ty: t_a, mutbl: mutbl_a}), &ty::ty_ptr(mt_b)) => {
|
||||
self.unpack_actual_value(t_a, |a| {
|
||||
match self.unsize_ty(t_a, a, mt_b.ty) {
|
||||
Some((ty, kind)) => {
|
||||
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
|
||||
return Err(ty::terr_mutability);
|
||||
}
|
||||
|
||||
let ty = ty::mk_ptr(self.tcx(),
|
||||
ty::mt{ty: ty, mutbl: mt_b.mutbl});
|
||||
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoPtr(AutoUnsize({:?})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
|
||||
Some(box AutoUnsize(kind))))
|
||||
})))
|
||||
match self.unsize_ty(t_a, mt_b.ty) {
|
||||
Some((ty, kind)) => {
|
||||
if !can_coerce_mutbls(mutbl_a, mt_b.mutbl) {
|
||||
return Err(ty::terr_mutability);
|
||||
}
|
||||
_ => Err(ty::terr_mismatch)
|
||||
|
||||
let ty = ty::mk_ptr(self.tcx(),
|
||||
ty::mt{ty: ty, mutbl: mt_b.mutbl});
|
||||
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoPtr(AutoUnsize({:?})))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoUnsafe(mt_b.mutbl,
|
||||
Some(box AutoUnsize(kind))))
|
||||
})))
|
||||
}
|
||||
})
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
}
|
||||
(&ty::ty_uniq(t_a), &ty::ty_uniq(t_b)) => {
|
||||
self.unpack_actual_value(t_a, |a| {
|
||||
match self.unsize_ty(t_a, a, t_b) {
|
||||
Some((ty, kind)) => {
|
||||
let ty = ty::mk_uniq(self.tcx(), ty);
|
||||
try!(self.fcx.infcx().try(|_| self.subtype(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoUnsizeUniq({:?}))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoUnsizeUniq(kind))
|
||||
})))
|
||||
}
|
||||
_ => Err(ty::terr_mismatch)
|
||||
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)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoUnsizeUniq({:?}))", kind);
|
||||
Ok(Some(AdjustDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoUnsizeUniq(kind))
|
||||
})))
|
||||
}
|
||||
})
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
}
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
|
@ -332,113 +326,112 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
|
|||
// E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
|
||||
fn unsize_ty(&self,
|
||||
ty_a: Ty<'tcx>,
|
||||
a: Ty<'tcx>,
|
||||
ty_b: Ty<'tcx>)
|
||||
-> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)> {
|
||||
debug!("unsize_ty(a={:?}, ty_b={})", a, ty_b.repr(self.tcx()));
|
||||
|
||||
-> Option<(Ty<'tcx>, ty::UnsizeKind<'tcx>)>
|
||||
{
|
||||
let tcx = self.tcx();
|
||||
|
||||
self.unpack_actual_value(ty_b, |b|
|
||||
match (&a.sty, &b.sty) {
|
||||
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
|
||||
let ty = ty::mk_vec(tcx, t_a, None);
|
||||
Some((ty, ty::UnsizeLength(len)))
|
||||
}
|
||||
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
|
||||
// Upcasts permit two things:
|
||||
//
|
||||
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
|
||||
//
|
||||
// Note that neither of these changes requires any
|
||||
// change at runtime. Eventually this will be
|
||||
// generalized.
|
||||
//
|
||||
// We always upcast when we can because of reason
|
||||
// #2 (region bounds).
|
||||
if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
|
||||
// construct a type `a1` which is a version of
|
||||
// `a` using the upcast bounds from `b`
|
||||
let bounds_a1 = ty::ExistentialBounds {
|
||||
// From type b
|
||||
region_bound: data_b.bounds.region_bound,
|
||||
builtin_bounds: data_b.bounds.builtin_bounds,
|
||||
|
||||
// From type a
|
||||
projection_bounds: data_a.bounds.projection_bounds.clone(),
|
||||
};
|
||||
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
|
||||
|
||||
// relate `a1` to `b`
|
||||
let result = self.fcx.infcx().try(|_| {
|
||||
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
|
||||
try!(self.outlives(data_a.bounds.region_bound,
|
||||
data_b.bounds.region_bound));
|
||||
self.subtype(ty_a1, ty_b)
|
||||
});
|
||||
|
||||
// if that was successful, we have a coercion
|
||||
match result {
|
||||
Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
|
||||
Err(_) => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
self.unpack_actual_value(ty_a, |a| {
|
||||
self.unpack_actual_value(ty_b, |b| {
|
||||
debug!("unsize_ty(a={}, b={})", a.repr(self.tcx()), b.repr(self.tcx()));
|
||||
match (&a.sty, &b.sty) {
|
||||
(&ty::ty_vec(t_a, Some(len)), &ty::ty_vec(_, None)) => {
|
||||
let ty = ty::mk_vec(tcx, t_a, None);
|
||||
Some((ty, ty::UnsizeLength(len)))
|
||||
}
|
||||
}
|
||||
(_, &ty::ty_trait(ref data)) => {
|
||||
Some((ty_b, ty::UnsizeVtable(ty::TyTrait { principal: data.principal.clone(),
|
||||
bounds: data.bounds.clone() },
|
||||
ty_a)))
|
||||
}
|
||||
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
|
||||
if did_a == did_b => {
|
||||
debug!("unsizing a struct");
|
||||
// Try unsizing each type param in turn to see if we end up with ty_b.
|
||||
let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
|
||||
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
|
||||
assert!(ty_substs_a.len() == ty_substs_b.len());
|
||||
(&ty::ty_trait(ref data_a), &ty::ty_trait(ref data_b)) => {
|
||||
// Upcasts permit two things:
|
||||
//
|
||||
// 1. Dropping builtin bounds, e.g. `Foo+Send` to `Foo`
|
||||
// 2. Tightening the region bound, e.g. `Foo+'a` to `Foo+'b` if `'a : 'b`
|
||||
//
|
||||
// Note that neither of these changes requires any
|
||||
// change at runtime. Eventually this will be
|
||||
// generalized.
|
||||
//
|
||||
// We always upcast when we can because of reason
|
||||
// #2 (region bounds).
|
||||
if data_a.bounds.builtin_bounds.is_superset(&data_b.bounds.builtin_bounds) {
|
||||
// construct a type `a1` which is a version of
|
||||
// `a` using the upcast bounds from `b`
|
||||
let bounds_a1 = ty::ExistentialBounds {
|
||||
// From type b
|
||||
region_bound: data_b.bounds.region_bound,
|
||||
builtin_bounds: data_b.bounds.builtin_bounds,
|
||||
|
||||
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() {
|
||||
continue;
|
||||
// From type a
|
||||
projection_bounds: data_a.bounds.projection_bounds.clone(),
|
||||
};
|
||||
let ty_a1 = ty::mk_trait(tcx, data_a.principal.clone(), bounds_a1);
|
||||
|
||||
// relate `a1` to `b`
|
||||
let result = self.fcx.infcx().try(|_| {
|
||||
// it's ok to upcast from Foo+'a to Foo+'b so long as 'a : 'b
|
||||
try!(self.outlives(data_a.bounds.region_bound,
|
||||
data_b.bounds.region_bound));
|
||||
self.subtype(ty_a1, ty_b)
|
||||
});
|
||||
|
||||
// if that was successful, we have a coercion
|
||||
match result {
|
||||
Ok(_) => Some((ty_b, ty::UnsizeUpcast(ty_b))),
|
||||
Err(_) => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
match
|
||||
self.unpack_actual_value(
|
||||
*tp_a,
|
||||
|tp| self.unsize_ty(*tp_a, tp, *tp_b))
|
||||
{
|
||||
Some((new_tp, k)) => {
|
||||
// Check that the whole types match.
|
||||
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() {
|
||||
debug!("Unsized type parameter '{}', but still \
|
||||
could not match types {} and {}",
|
||||
ppaux::ty_to_string(tcx, *tp_a),
|
||||
ppaux::ty_to_string(tcx, ty),
|
||||
ppaux::ty_to_string(tcx, ty_b));
|
||||
// We can only unsize a single type parameter, so
|
||||
// if we unsize one and it doesn't give us the
|
||||
// type we want, then we won't succeed later.
|
||||
}
|
||||
(_, &ty::ty_trait(ref data)) => {
|
||||
Some((ty_b, ty::UnsizeVtable(ty::TyTrait {
|
||||
principal: data.principal.clone(),
|
||||
bounds: data.bounds.clone()
|
||||
},
|
||||
ty_a)))
|
||||
}
|
||||
(&ty::ty_struct(did_a, substs_a), &ty::ty_struct(did_b, substs_b))
|
||||
if did_a == did_b => {
|
||||
debug!("unsizing a struct");
|
||||
// Try unsizing each type param in turn to see if we end up with ty_b.
|
||||
let ty_substs_a = substs_a.types.get_slice(subst::TypeSpace);
|
||||
let ty_substs_b = substs_b.types.get_slice(subst::TypeSpace);
|
||||
assert!(ty_substs_a.len() == ty_substs_b.len());
|
||||
|
||||
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() {
|
||||
continue;
|
||||
}
|
||||
match self.unsize_ty(*tp_a, *tp_b) {
|
||||
Some((new_tp, k)) => {
|
||||
// Check that the whole types match.
|
||||
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() {
|
||||
debug!("Unsized type parameter '{}', but still \
|
||||
could not match types {} and {}",
|
||||
ppaux::ty_to_string(tcx, *tp_a),
|
||||
ppaux::ty_to_string(tcx, ty),
|
||||
ppaux::ty_to_string(tcx, ty_b));
|
||||
// We can only unsize a single type parameter, so
|
||||
// if we unsize one and it doesn't give us the
|
||||
// type we want, then we won't succeed later.
|
||||
break;
|
||||
}
|
||||
|
||||
result = Some((ty, ty::UnsizeStruct(box k, i)));
|
||||
break;
|
||||
}
|
||||
|
||||
result = Some((ty, ty::UnsizeStruct(box k, i)));
|
||||
break;
|
||||
None => {}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
result
|
||||
}
|
||||
result
|
||||
_ => None
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn coerce_from_fn_pointer(&self,
|
||||
|
|
|
@ -53,9 +53,11 @@ pub fn eqtype<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
|
|||
}
|
||||
}
|
||||
|
||||
// Checks that the type `actual` can be coerced to `expected`.
|
||||
pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, sp: Span,
|
||||
expected: Ty<'tcx>, expr: &ast::Expr) {
|
||||
// Checks that the type of `expr` can be coerced to `expected`.
|
||||
pub fn coerce<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
sp: Span,
|
||||
expected: Ty<'tcx>,
|
||||
expr: &ast::Expr) {
|
||||
let expr_ty = fcx.expr_ty(expr);
|
||||
debug!("demand::coerce(expected = {}, expr_ty = {})",
|
||||
expected.repr(fcx.ccx.tcx),
|
||||
|
|
|
@ -12,13 +12,249 @@ use check::regionck::{self, Rcx};
|
|||
|
||||
use middle::infer;
|
||||
use middle::region;
|
||||
use middle::subst;
|
||||
use middle::subst::{self, Subst};
|
||||
use middle::ty::{self, Ty};
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap::{self, Span};
|
||||
|
||||
/// check_drop_impl confirms that the Drop implementation identfied by
|
||||
/// `drop_impl_did` is not any more specialized than the type it is
|
||||
/// attached to (Issue #8142).
|
||||
///
|
||||
/// This means:
|
||||
///
|
||||
/// 1. The self type must be nominal (this is already checked during
|
||||
/// coherence),
|
||||
///
|
||||
/// 2. The generic region/type parameters of the impl's self-type must
|
||||
/// all be parameters of the Drop impl itself (i.e. no
|
||||
/// specialization like `impl Drop for Foo<i32>`), and,
|
||||
///
|
||||
/// 3. Any bounds on the generic parameters must be reflected in the
|
||||
/// struct/enum definition for the nominal type itself (i.e.
|
||||
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
||||
///
|
||||
pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ()> {
|
||||
let ty::TypeScheme { generics: ref dtor_generics,
|
||||
ty: ref dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did);
|
||||
let dtor_predicates = ty::lookup_predicates(tcx, drop_impl_did);
|
||||
match dtor_self_type.sty {
|
||||
ty::ty_enum(self_type_did, self_to_impl_substs) |
|
||||
ty::ty_struct(self_type_did, self_to_impl_substs) |
|
||||
ty::ty_closure(self_type_did, self_to_impl_substs) => {
|
||||
try!(ensure_drop_params_and_item_params_correspond(tcx,
|
||||
drop_impl_did,
|
||||
dtor_generics,
|
||||
dtor_self_type,
|
||||
self_type_did));
|
||||
|
||||
ensure_drop_predicates_are_implied_by_item_defn(tcx,
|
||||
drop_impl_did,
|
||||
&dtor_predicates,
|
||||
self_type_did,
|
||||
self_to_impl_substs)
|
||||
}
|
||||
_ => {
|
||||
// Destructors only work on nominal types. This was
|
||||
// already checked by coherence, so we can panic here.
|
||||
let span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
|
||||
tcx.sess.span_bug(
|
||||
span, &format!("should have been rejected by coherence check: {}",
|
||||
dtor_self_type.repr(tcx)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn ensure_drop_params_and_item_params_correspond<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
drop_impl_did: ast::DefId,
|
||||
drop_impl_generics: &ty::Generics<'tcx>,
|
||||
drop_impl_ty: &ty::Ty<'tcx>,
|
||||
self_type_did: ast::DefId) -> Result<(), ()>
|
||||
{
|
||||
// New strategy based on review suggestion from nikomatsakis.
|
||||
//
|
||||
// (In the text and code below, "named" denotes "struct/enum", and
|
||||
// "generic params" denotes "type and region params")
|
||||
//
|
||||
// 1. Create fresh skolemized type/region "constants" for each of
|
||||
// the named type's generic params. Instantiate the named type
|
||||
// with the fresh constants, yielding `named_skolem`.
|
||||
//
|
||||
// 2. Create unification variables for each of the Drop impl's
|
||||
// generic params. Instantiate the impl's Self's type with the
|
||||
// unification-vars, yielding `drop_unifier`.
|
||||
//
|
||||
// 3. Attempt to unify Self_unif with Type_skolem. If unification
|
||||
// succeeds, continue (i.e. with the predicate checks).
|
||||
|
||||
let ty::TypeScheme { generics: ref named_type_generics,
|
||||
ty: named_type } =
|
||||
ty::lookup_item_type(tcx, self_type_did);
|
||||
|
||||
let infcx = infer::new_infer_ctxt(tcx);
|
||||
infcx.try(|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);
|
||||
|
||||
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
|
||||
let drop_to_unifier =
|
||||
infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
|
||||
let drop_unifier = drop_impl_ty.subst(tcx, &drop_to_unifier);
|
||||
|
||||
if let Ok(()) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
|
||||
named_type_skolem, drop_unifier) {
|
||||
// Even if we did manage to equate the types, the process
|
||||
// may have just gathered unsolvable region constraints
|
||||
// like `R == 'static` (represented as a pair of subregion
|
||||
// constraints) for some skolemization constant R.
|
||||
//
|
||||
// However, the leak_check method allows us to confirm
|
||||
// that no skolemized regions escaped (i.e. were related
|
||||
// to other regions in the constraint graph).
|
||||
if let Ok(()) = infcx.leak_check(&skol_map, snapshot) {
|
||||
return Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
span_err!(tcx.sess, drop_impl_span, E0366,
|
||||
"Implementations of Drop cannot be specialized");
|
||||
let item_span = tcx.map.span(self_type_did.node);
|
||||
tcx.sess.span_note(item_span,
|
||||
"Use same sequence of generic type and region \
|
||||
parameters that is on the struct/enum definition");
|
||||
return Err(());
|
||||
})
|
||||
}
|
||||
|
||||
/// Confirms that every predicate imposed by dtor_predicates is
|
||||
/// implied by assuming the predicates attached to self_type_did.
|
||||
fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
|
||||
tcx: &ty::ctxt<'tcx>,
|
||||
drop_impl_did: ast::DefId,
|
||||
dtor_predicates: &ty::GenericPredicates<'tcx>,
|
||||
self_type_did: ast::DefId,
|
||||
self_to_impl_substs: &subst::Substs<'tcx>) -> Result<(), ()> {
|
||||
|
||||
// Here is an example, analogous to that from
|
||||
// `compare_impl_method`.
|
||||
//
|
||||
// Consider a struct type:
|
||||
//
|
||||
// struct Type<'c, 'b:'c, 'a> {
|
||||
// x: &'a Contents // (contents are irrelevant;
|
||||
// y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.)
|
||||
// }
|
||||
//
|
||||
// and a Drop impl:
|
||||
//
|
||||
// impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
|
||||
// fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
|
||||
// }
|
||||
//
|
||||
// We start out with self_to_impl_substs, that maps the generic
|
||||
// parameters of Type to that of the Drop impl.
|
||||
//
|
||||
// self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
|
||||
//
|
||||
// Applying this to the predicates (i.e. assumptions) provided by the item
|
||||
// definition yields the instantiated assumptions:
|
||||
//
|
||||
// ['y : 'z]
|
||||
//
|
||||
// We then check all of the predicates of the Drop impl:
|
||||
//
|
||||
// ['y:'z, 'x:'y]
|
||||
//
|
||||
// and ensure each is in the list of instantiated
|
||||
// assumptions. Here, `'y:'z` is present, but `'x:'y` is
|
||||
// absent. So we report an error that the Drop impl injected a
|
||||
// predicate that is not present on the struct definition.
|
||||
|
||||
assert_eq!(self_type_did.krate, ast::LOCAL_CRATE);
|
||||
|
||||
let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
|
||||
|
||||
// We can assume the predicates attached to struct/enum definition
|
||||
// hold.
|
||||
let generic_assumptions = ty::lookup_predicates(tcx, self_type_did);
|
||||
|
||||
let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
|
||||
assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::SelfSpace));
|
||||
assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::FnSpace));
|
||||
let assumptions_in_impl_context =
|
||||
assumptions_in_impl_context.predicates.get_slice(subst::TypeSpace);
|
||||
|
||||
// An earlier version of this code attempted to do this checking
|
||||
// via the traits::fulfill machinery. However, it ran into trouble
|
||||
// since the fulfill machinery merely turns outlives-predicates
|
||||
// 'a:'b and T:'b into region inference constraints. It is simpler
|
||||
// just to look for all the predicates directly.
|
||||
|
||||
assert!(dtor_predicates.predicates.is_empty_in(subst::SelfSpace));
|
||||
assert!(dtor_predicates.predicates.is_empty_in(subst::FnSpace));
|
||||
let predicates = dtor_predicates.predicates.get_slice(subst::TypeSpace);
|
||||
for predicate in predicates {
|
||||
// (We do not need to worry about deep analysis of type
|
||||
// expressions etc because the Drop impls are already forced
|
||||
// to take on a structure that is roughly a alpha-renaming of
|
||||
// the generic parameters of the item definition.)
|
||||
|
||||
// This path now just checks *all* predicates via the direct
|
||||
// lookup, rather than using fulfill machinery.
|
||||
//
|
||||
// However, it may be more efficient in the future to batch
|
||||
// the analysis together via the fulfill , rather than the
|
||||
// repeated `contains` calls.
|
||||
|
||||
if !assumptions_in_impl_context.contains(&predicate) {
|
||||
let item_span = tcx.map.span(self_type_did.node);
|
||||
let req = predicate.user_string(tcx);
|
||||
span_err!(tcx.sess, drop_impl_span, E0367,
|
||||
"The requirement `{}` is added only by the Drop impl.", req);
|
||||
tcx.sess.span_note(item_span,
|
||||
"The same requirement must be part of \
|
||||
the struct/enum definition");
|
||||
}
|
||||
}
|
||||
|
||||
if tcx.sess.has_errors() {
|
||||
return Err(());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// check_safety_of_destructor_if_necessary confirms that the type
|
||||
/// expression `typ` conforms to the "Drop Check Rule" from the Sound
|
||||
/// Generic Drop (RFC 769).
|
||||
///
|
||||
/// ----
|
||||
///
|
||||
/// The Drop Check Rule is the following:
|
||||
///
|
||||
/// Let `v` be some value (either temporary or named) and 'a be some
|
||||
/// lifetime (scope). If the type of `v` owns data of type `D`, where
|
||||
///
|
||||
/// (1.) `D` has a lifetime- or type-parametric Drop implementation, and
|
||||
/// (2.) the structure of `D` can reach a reference of type `&'a _`, and
|
||||
/// (3.) either:
|
||||
///
|
||||
/// (A.) the Drop impl for `D` instantiates `D` at 'a directly,
|
||||
/// i.e. `D<'a>`, or,
|
||||
///
|
||||
/// (B.) the Drop impl for `D` has some type parameter with a
|
||||
/// trait bound `T` where `T` is a trait that has at least
|
||||
/// one method,
|
||||
///
|
||||
/// then 'a must strictly outlive the scope of v.
|
||||
///
|
||||
/// ----
|
||||
///
|
||||
/// This function is meant to by applied to the type for every
|
||||
/// expression in the program.
|
||||
pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
|
||||
typ: ty::Ty<'tcx>,
|
||||
span: Span,
|
||||
|
|
|
@ -725,7 +725,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
|
|||
};
|
||||
|
||||
// this closure doesn't implement the right kind of `Fn` trait
|
||||
if closure_kind != kind {
|
||||
if !closure_kind.extends(kind) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,6 +184,8 @@ pub struct Inherited<'a, 'tcx: 'a> {
|
|||
// def-id of the closure, so that once we decide, we can easily go
|
||||
// back and process them.
|
||||
deferred_call_resolutions: RefCell<DefIdMap<Vec<DeferredCallResolutionHandler<'tcx>>>>,
|
||||
|
||||
deferred_cast_checks: RefCell<Vec<CastCheck<'tcx>>>,
|
||||
}
|
||||
|
||||
trait DeferredCallResolution<'tcx> {
|
||||
|
@ -192,6 +194,15 @@ trait DeferredCallResolution<'tcx> {
|
|||
|
||||
type DeferredCallResolutionHandler<'tcx> = Box<DeferredCallResolution<'tcx>+'tcx>;
|
||||
|
||||
/// Reifies a cast check to be checked once we have full type information for
|
||||
/// a function context.
|
||||
struct CastCheck<'tcx> {
|
||||
expr: ast::Expr,
|
||||
expr_ty: Ty<'tcx>,
|
||||
cast_ty: Ty<'tcx>,
|
||||
span: Span,
|
||||
}
|
||||
|
||||
/// When type-checking an expression, we propagate downward
|
||||
/// whatever type hint we are able in the form of an `Expectation`.
|
||||
#[derive(Copy)]
|
||||
|
@ -399,6 +410,7 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> {
|
|||
fn_sig_map: RefCell::new(NodeMap()),
|
||||
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
|
||||
deferred_call_resolutions: RefCell::new(DefIdMap()),
|
||||
deferred_cast_checks: RefCell::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -478,6 +490,20 @@ pub fn check_item_types(ccx: &CrateCtxt) {
|
|||
visit::walk_crate(&mut visit, krate);
|
||||
|
||||
ccx.tcx.sess.abort_if_errors();
|
||||
|
||||
for drop_method_did in ccx.tcx.destructors.borrow().iter() {
|
||||
if drop_method_did.krate == ast::LOCAL_CRATE {
|
||||
let drop_impl_did = ccx.tcx.map.get_parent_did(drop_method_did.node);
|
||||
match dropck::check_drop_impl(ccx.tcx, drop_impl_did) {
|
||||
Ok(()) => {}
|
||||
Err(()) => {
|
||||
assert!(ccx.tcx.sess.has_errors());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ccx.tcx.sess.abort_if_errors();
|
||||
}
|
||||
|
||||
fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
||||
|
@ -508,6 +534,7 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
|
|||
vtable::select_all_fcx_obligations_and_apply_defaults(&fcx);
|
||||
upvar::closure_analyze_fn(&fcx, fn_id, decl, body);
|
||||
vtable::select_all_fcx_obligations_or_error(&fcx);
|
||||
fcx.check_casts();
|
||||
regionck::regionck_fn(&fcx, fn_id, fn_span, decl, body);
|
||||
writeback::resolve_type_vars_in_fn(&fcx, decl, body);
|
||||
}
|
||||
|
@ -1053,11 +1080,7 @@ fn report_cast_to_unsized_type<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
|
||||
|
||||
fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
t_1: Ty<'tcx>,
|
||||
t_e: Ty<'tcx>,
|
||||
e: &ast::Expr) {
|
||||
fn check_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>, cast: &CastCheck<'tcx>) {
|
||||
fn cast_through_integer_err<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
span: Span,
|
||||
t_1: Ty<'tcx>,
|
||||
|
@ -1070,6 +1093,33 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}, t_e, None);
|
||||
}
|
||||
|
||||
let span = cast.span;
|
||||
let e = &cast.expr;
|
||||
let t_e = structurally_resolved_type(fcx, span, cast.expr_ty);
|
||||
let t_1 = structurally_resolved_type(fcx, span, cast.cast_ty);
|
||||
|
||||
// Check for trivial casts.
|
||||
if !ty::type_has_ty_infer(t_1) {
|
||||
if let Ok(()) = coercion::mk_assignty(fcx, e, t_e, t_1) {
|
||||
if ty::type_is_numeric(t_1) && ty::type_is_numeric(t_e) {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_NUMERIC_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial numeric cast: `{}` as `{}`",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
} else {
|
||||
fcx.tcx().sess.add_lint(lint::builtin::TRIVIAL_CASTS,
|
||||
e.id,
|
||||
span,
|
||||
format!("trivial cast: `{}` as `{}`",
|
||||
fcx.infcx().ty_to_string(t_e),
|
||||
fcx.infcx().ty_to_string(t_1)));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let t_e_is_bare_fn_item = ty::type_is_bare_fn_item(t_e);
|
||||
let t_e_is_scalar = ty::type_is_scalar(t_e);
|
||||
let t_e_is_integral = ty::type_is_integral(t_e);
|
||||
|
@ -1085,18 +1135,17 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
let t_1_is_trivial = t_1_is_scalar && !t_1_is_char && !t_1_is_bare_fn;
|
||||
|
||||
if t_e_is_bare_fn_item && t_1_is_bare_fn {
|
||||
demand::coerce(fcx, e.span, t_1, &*e);
|
||||
demand::coerce(fcx, e.span, t_1, &e);
|
||||
} else if t_1_is_char {
|
||||
let t_e = fcx.infcx().shallow_resolve(t_e);
|
||||
if t_e.sty != ty::ty_uint(ast::TyU8) {
|
||||
fcx.type_error_message(span, |actual| {
|
||||
format!("only `u8` can be cast as \
|
||||
`char`, not `{}`", actual)
|
||||
format!("only `u8` can be cast as `char`, not `{}`", actual)
|
||||
}, t_e, None);
|
||||
}
|
||||
} else if t_1.sty == ty::ty_bool {
|
||||
span_err!(fcx.tcx().sess, span, E0054,
|
||||
"cannot cast as `bool`, compare with zero instead");
|
||||
"cannot cast as `bool`, compare with zero instead");
|
||||
} else if t_1_is_float && (t_e_is_scalar || t_e_is_c_enum) && !(
|
||||
t_e_is_integral || t_e_is_float || t_e.sty == ty::ty_bool) {
|
||||
// Casts to float must go through an integer or boolean
|
||||
|
@ -1145,7 +1194,7 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
/* this case is allowed */
|
||||
}
|
||||
_ => {
|
||||
demand::coerce(fcx, e.span, t_1, &*e);
|
||||
demand::coerce(fcx, e.span, t_1, &e);
|
||||
}
|
||||
}
|
||||
} else if !(t_e_is_scalar && t_1_is_trivial) {
|
||||
|
@ -1162,49 +1211,6 @@ fn check_cast_inner<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
}
|
||||
}
|
||||
|
||||
fn check_cast<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
|
||||
cast_expr: &ast::Expr,
|
||||
e: &'tcx ast::Expr,
|
||||
t: &ast::Ty) {
|
||||
let id = cast_expr.id;
|
||||
let span = cast_expr.span;
|
||||
|
||||
// Find the type of `e`. Supply hints based on the type we are casting to,
|
||||
// if appropriate.
|
||||
let t_1 = fcx.to_ty(t);
|
||||
let t_1 = structurally_resolved_type(fcx, span, t_1);
|
||||
|
||||
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
|
||||
|
||||
let t_e = fcx.expr_ty(e);
|
||||
|
||||
debug!("t_1={}", fcx.infcx().ty_to_string(t_1));
|
||||
debug!("t_e={}", fcx.infcx().ty_to_string(t_e));
|
||||
|
||||
if ty::type_is_error(t_e) {
|
||||
fcx.write_error(id);
|
||||
return
|
||||
}
|
||||
|
||||
if !fcx.type_is_known_to_be_sized(t_1, cast_expr.span) {
|
||||
report_cast_to_unsized_type(fcx, span, t.span, e.span, t_1, t_e, id);
|
||||
return
|
||||
}
|
||||
|
||||
if ty::type_is_trait(t_1) {
|
||||
// This will be looked up later on.
|
||||
vtable::check_object_cast(fcx, cast_expr, e, t_1);
|
||||
fcx.write_ty(id, t_1);
|
||||
return
|
||||
}
|
||||
|
||||
let t_1 = structurally_resolved_type(fcx, span, t_1);
|
||||
let t_e = structurally_resolved_type(fcx, span, t_e);
|
||||
|
||||
check_cast_inner(fcx, span, t_1, t_e, e);
|
||||
fcx.write_ty(id, t_1);
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
fn tcx(&self) -> &ty::ctxt<'tcx> { self.ccx.tcx }
|
||||
|
||||
|
@ -1372,7 +1378,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
}
|
||||
|
||||
pub fn tag(&self) -> String {
|
||||
format!("{:?}", self as *const FnCtxt)
|
||||
let self_ptr: *const FnCtxt = self;
|
||||
format!("{:?}", self_ptr)
|
||||
}
|
||||
|
||||
pub fn local_ty(&self, span: Span, nid: ast::NodeId) -> Ty<'tcx> {
|
||||
|
@ -1416,14 +1423,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
self.inh.node_types.borrow_mut().insert(node_id, ty);
|
||||
}
|
||||
|
||||
pub fn write_object_cast(&self,
|
||||
key: ast::NodeId,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>) {
|
||||
debug!("write_object_cast key={} trait_ref={}",
|
||||
key, trait_ref.repr(self.tcx()));
|
||||
self.inh.object_cast_map.borrow_mut().insert(key, trait_ref);
|
||||
}
|
||||
|
||||
pub fn write_substs(&self, node_id: ast::NodeId, substs: ty::ItemSubsts<'tcx>) {
|
||||
if !substs.substs.is_noop() {
|
||||
debug!("write_substs({}, {}) in fcx {}",
|
||||
|
@ -1923,6 +1922,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
o_field.map(|f| ty::lookup_field_type(self.tcx(), class_id, f.id, substs))
|
||||
.map(|t| self.normalize_associated_types_in(span, &t))
|
||||
}
|
||||
|
||||
fn check_casts(&self) {
|
||||
let mut deferred_cast_checks = self.inh.deferred_cast_checks.borrow_mut();
|
||||
for check in deferred_cast_checks.iter() {
|
||||
check_cast(self, check);
|
||||
}
|
||||
|
||||
deferred_cast_checks.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> RegionScope for FnCtxt<'a, 'tcx> {
|
||||
|
@ -3828,7 +3836,33 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
if let ast::TyFixedLengthVec(_, ref count_expr) = t.node {
|
||||
check_expr_with_hint(fcx, &**count_expr, tcx.types.uint);
|
||||
}
|
||||
check_cast(fcx, expr, &**e, &**t);
|
||||
|
||||
// Find the type of `e`. Supply hints based on the type we are casting to,
|
||||
// if appropriate.
|
||||
let t_1 = fcx.to_ty(t);
|
||||
let t_1 = structurally_resolved_type(fcx, expr.span, t_1);
|
||||
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1));
|
||||
let t_e = fcx.expr_ty(e);
|
||||
|
||||
// Eagerly check for some obvious errors.
|
||||
if ty::type_is_error(t_e) {
|
||||
fcx.write_error(id);
|
||||
} else if !fcx.type_is_known_to_be_sized(t_1, expr.span) {
|
||||
report_cast_to_unsized_type(fcx, expr.span, t.span, e.span, t_1, t_e, id);
|
||||
} else {
|
||||
// Write a type for the whole expression, assuming everything is going
|
||||
// to work out Ok.
|
||||
fcx.write_ty(id, t_1);
|
||||
|
||||
// Defer other checks until we're done type checking.
|
||||
let mut deferred_cast_checks = fcx.inh.deferred_cast_checks.borrow_mut();
|
||||
deferred_cast_checks.push(CastCheck {
|
||||
expr: (**e).clone(),
|
||||
expr_ty: t_e,
|
||||
cast_ty: t_1,
|
||||
span: expr.span,
|
||||
});
|
||||
}
|
||||
}
|
||||
ast::ExprVec(ref args) => {
|
||||
let uty = expected.to_option(fcx).and_then(|uty| {
|
||||
|
@ -4461,6 +4495,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
|||
check_expr_with_hint(fcx, e, declty);
|
||||
demand::coerce(fcx, e.span, declty, e);
|
||||
vtable::select_all_fcx_obligations_or_error(fcx);
|
||||
fcx.check_casts();
|
||||
regionck::regionck_expr(fcx, e);
|
||||
writeback::resolve_type_vars_in_expr(fcx, e);
|
||||
}
|
||||
|
@ -4560,6 +4595,8 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
ty: attr::IntType,
|
||||
disr: ty::Disr) -> bool {
|
||||
fn uint_in_range(ccx: &CrateCtxt, ty: ast::UintTy, disr: ty::Disr) -> bool {
|
||||
#![allow(trivial_numeric_casts)]
|
||||
|
||||
match ty {
|
||||
ast::TyU8 => disr as u8 as Disr == disr,
|
||||
ast::TyU16 => disr as u16 as Disr == disr,
|
||||
|
@ -4588,6 +4625,7 @@ pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
|
|||
id: ast::NodeId,
|
||||
hint: attr::ReprAttr)
|
||||
-> Vec<Rc<ty::VariantInfo<'tcx>>> {
|
||||
#![allow(trivial_numeric_casts)]
|
||||
use std::num::Int;
|
||||
|
||||
let rty = ty::node_id_to_type(ccx.tcx, id);
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
// except according to those terms.
|
||||
|
||||
use check::{FnCtxt};
|
||||
use check::demand;
|
||||
use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
|
||||
use middle::traits::{Obligation, ObligationCause};
|
||||
use middle::traits::report_fulfillment_errors;
|
||||
|
@ -19,83 +18,6 @@ use syntax::codemap::Span;
|
|||
use util::nodemap::FnvHashSet;
|
||||
use util::ppaux::{Repr, UserString};
|
||||
|
||||
pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
cast_expr: &ast::Expr,
|
||||
source_expr: &ast::Expr,
|
||||
target_object_ty: Ty<'tcx>)
|
||||
{
|
||||
let tcx = fcx.tcx();
|
||||
debug!("check_object_cast(cast_expr={}, target_object_ty={})",
|
||||
cast_expr.repr(tcx),
|
||||
target_object_ty.repr(tcx));
|
||||
|
||||
// Look up vtables for the type we're casting to,
|
||||
// passing in the source and target type. The source
|
||||
// must be a pointer type suitable to the object sigil,
|
||||
// e.g.: `&x as &Trait` or `box x as Box<Trait>`
|
||||
|
||||
// First, construct a fresh type that we can feed into `<expr>`
|
||||
// within `<expr> as <type>` to inform type inference (e.g. to
|
||||
// tell it that we are expecting a `Box<_>` or an `&_`).
|
||||
let fresh_ty = fcx.infcx().next_ty_var();
|
||||
let (object_trait_ty, source_expected_ty) = match target_object_ty.sty {
|
||||
ty::ty_uniq(object_trait_ty) => {
|
||||
(object_trait_ty, ty::mk_uniq(fcx.tcx(), fresh_ty))
|
||||
}
|
||||
ty::ty_rptr(target_region, ty::mt { ty: object_trait_ty,
|
||||
mutbl: target_mutbl }) => {
|
||||
(object_trait_ty,
|
||||
ty::mk_rptr(fcx.tcx(),
|
||||
target_region, ty::mt { ty: fresh_ty,
|
||||
mutbl: target_mutbl }))
|
||||
}
|
||||
_ => {
|
||||
fcx.tcx().sess.span_bug(source_expr.span, "expected object type");
|
||||
}
|
||||
};
|
||||
|
||||
let source_ty = fcx.expr_ty(source_expr);
|
||||
debug!("check_object_cast pre unify source_ty={}", source_ty.repr(tcx));
|
||||
|
||||
// This ensures that the source_ty <: source_expected_ty, which
|
||||
// will ensure e.g. that &'a T <: &'b T when doing `&'a T as &'b Trait`
|
||||
//
|
||||
// FIXME (pnkfelix): do we need to use suptype_with_fn in order to
|
||||
// override the error message emitted when the types do not work
|
||||
// out in the manner desired?
|
||||
demand::suptype(fcx, source_expr.span, source_expected_ty, source_ty);
|
||||
|
||||
debug!("check_object_cast postunify source_ty={}", source_ty.repr(tcx));
|
||||
|
||||
let object_trait = object_trait(&object_trait_ty);
|
||||
|
||||
// Ensure that if Ptr<T> is cast to Ptr<Trait>, then T : Trait.
|
||||
push_cast_obligation(fcx, cast_expr, object_trait, fresh_ty);
|
||||
check_object_safety(tcx, object_trait, source_expr.span);
|
||||
|
||||
fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
|
||||
match t.sty {
|
||||
ty::ty_trait(ref ty_trait) => &**ty_trait,
|
||||
_ => panic!("expected ty_trait")
|
||||
}
|
||||
}
|
||||
|
||||
fn push_cast_obligation<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
|
||||
cast_expr: &ast::Expr,
|
||||
object_trait: &ty::TyTrait<'tcx>,
|
||||
referent_ty: Ty<'tcx>) {
|
||||
let object_trait_ref =
|
||||
register_object_cast_obligations(fcx,
|
||||
cast_expr.span,
|
||||
object_trait,
|
||||
referent_ty);
|
||||
|
||||
// Finally record the object_trait_ref for use during trans
|
||||
// (it would prob be better not to do this, but it's just kind
|
||||
// of a pain to have to reconstruct it).
|
||||
fcx.write_object_cast(cast_expr.id, object_trait_ref);
|
||||
}
|
||||
}
|
||||
|
||||
// Check that a trait is 'object-safe'. This should be checked whenever a trait object
|
||||
// is created (by casting or coercion, etc.). A trait is object-safe if all its
|
||||
|
|
|
@ -784,14 +784,15 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
&enum_definition.variants);
|
||||
},
|
||||
ast::ItemDefaultImpl(_, ref ast_trait_ref) => {
|
||||
let trait_ref = astconv::instantiate_trait_ref(&ccx.icx(&()),
|
||||
&ExplicitRscope,
|
||||
ast_trait_ref,
|
||||
Some(it.id),
|
||||
None,
|
||||
None);
|
||||
let trait_ref =
|
||||
astconv::instantiate_mono_trait_ref(&ccx.icx(&()),
|
||||
&ExplicitRscope,
|
||||
ast_trait_ref,
|
||||
None);
|
||||
|
||||
ty::record_trait_has_default_impl(tcx, trait_ref.def_id);
|
||||
|
||||
tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
|
||||
}
|
||||
ast::ItemImpl(_, _,
|
||||
ref generics,
|
||||
|
@ -890,13 +891,14 @@ fn convert_item(ccx: &CrateCtxt, it: &ast::Item) {
|
|||
}
|
||||
}
|
||||
|
||||
if let Some(ref trait_ref) = *opt_trait_ref {
|
||||
astconv::instantiate_trait_ref(&ccx.icx(&ty_predicates),
|
||||
&ExplicitRscope,
|
||||
trait_ref,
|
||||
Some(it.id),
|
||||
Some(selfty),
|
||||
None);
|
||||
if let Some(ref ast_trait_ref) = *opt_trait_ref {
|
||||
let trait_ref =
|
||||
astconv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
|
||||
&ExplicitRscope,
|
||||
ast_trait_ref,
|
||||
Some(selfty));
|
||||
|
||||
tcx.impl_trait_refs.borrow_mut().insert(it.id, trait_ref);
|
||||
}
|
||||
|
||||
enforce_impl_ty_params_are_constrained(tcx,
|
||||
|
|
|
@ -177,7 +177,9 @@ register_diagnostics! {
|
|||
E0319, // trait impls for defaulted traits allowed just for structs/enums
|
||||
E0320, // recursive overflow during dropck
|
||||
E0321, // extended coherence rules for defaulted traits violated
|
||||
E0322 // cannot implement Sized explicitly
|
||||
E0322, // cannot implement Sized explicitly
|
||||
E0366, // dropck forbid specialization to concrete type or region
|
||||
E0367 // dropck forbid specialization to predicate not in struct/enum
|
||||
}
|
||||
|
||||
__build_diagnostic_array! { DIAGNOSTICS }
|
||||
|
|
|
@ -308,8 +308,8 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
|
|||
};
|
||||
(*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
|
||||
= &mut opaque as *mut _ as *mut libc::c_void;
|
||||
(*renderer).blockcode = Some(block as blockcodefn);
|
||||
(*renderer).header = Some(header as headerfn);
|
||||
(*renderer).blockcode = Some(block);
|
||||
(*renderer).header = Some(header);
|
||||
|
||||
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
|
||||
hoedown_document_render(document, ob, s.as_ptr(),
|
||||
|
@ -380,8 +380,8 @@ pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector) {
|
|||
unsafe {
|
||||
let ob = hoedown_buffer_new(DEF_OUNIT);
|
||||
let renderer = hoedown_html_renderer_new(0, 0);
|
||||
(*renderer).blockcode = Some(block as blockcodefn);
|
||||
(*renderer).header = Some(header as headerfn);
|
||||
(*renderer).blockcode = Some(block);
|
||||
(*renderer).header = Some(header);
|
||||
(*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
|
||||
= tests as *mut _ as *mut libc::c_void;
|
||||
|
||||
|
@ -501,10 +501,10 @@ pub fn plain_summary_line(md: &str) -> String {
|
|||
unsafe {
|
||||
let ob = hoedown_buffer_new(DEF_OUNIT);
|
||||
let mut plain_renderer: hoedown_renderer = ::std::mem::zeroed();
|
||||
let renderer = &mut plain_renderer as *mut hoedown_renderer;
|
||||
let renderer: *mut hoedown_renderer = &mut plain_renderer;
|
||||
(*renderer).opaque = ob as *mut libc::c_void;
|
||||
(*renderer).link = Some(link as linkfn);
|
||||
(*renderer).normal_text = Some(normal_text as normaltextfn);
|
||||
(*renderer).link = Some(link);
|
||||
(*renderer).normal_text = Some(normal_text);
|
||||
|
||||
let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
|
||||
hoedown_document_render(document, ob, md.as_ptr(),
|
||||
|
|
|
@ -2429,7 +2429,10 @@ pub trait ToJson {
|
|||
macro_rules! to_json_impl_i64 {
|
||||
($($t:ty), +) => (
|
||||
$(impl ToJson for $t {
|
||||
fn to_json(&self) -> Json { Json::I64(*self as i64) }
|
||||
fn to_json(&self) -> Json {
|
||||
#![allow(trivial_numeric_casts)]
|
||||
Json::I64(*self as i64)
|
||||
}
|
||||
})+
|
||||
)
|
||||
}
|
||||
|
@ -2439,7 +2442,10 @@ to_json_impl_i64! { int, i8, i16, i32, i64 }
|
|||
macro_rules! to_json_impl_u64 {
|
||||
($($t:ty), +) => (
|
||||
$(impl ToJson for $t {
|
||||
fn to_json(&self) -> Json { Json::U64(*self as u64) }
|
||||
fn to_json(&self) -> Json {
|
||||
#![allow(trivial_numeric_casts)]
|
||||
Json::U64(*self as u64)
|
||||
}
|
||||
})+
|
||||
)
|
||||
}
|
||||
|
|
|
@ -128,6 +128,17 @@ impl File {
|
|||
///
|
||||
/// This function will return an error if `path` does not already exist.
|
||||
/// Other errors may also be returned according to `OpenOptions::open`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// let mut f = try!(File::open("foo.txt"));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<File> {
|
||||
OpenOptions::new().read(true).open(path)
|
||||
|
@ -139,6 +150,17 @@ impl File {
|
|||
/// and will truncate it if it does.
|
||||
///
|
||||
/// See the `OpenOptions::open` function for more details.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// let mut f = try!(File::create("foo.txt"));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn create<P: AsRef<Path>>(path: P) -> io::Result<File> {
|
||||
OpenOptions::new().write(true).create(true).truncate(true).open(path)
|
||||
|
@ -156,6 +178,21 @@ impl File {
|
|||
///
|
||||
/// This function will attempt to ensure that all in-core data reaches the
|
||||
/// filesystem before returning.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::io::prelude::*;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// let mut f = try!(File::create("foo.txt"));
|
||||
/// try!(f.write_all(b"Hello, world!"));
|
||||
///
|
||||
/// try!(f.sync_all());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn sync_all(&self) -> io::Result<()> {
|
||||
self.inner.fsync()
|
||||
|
@ -170,6 +207,21 @@ impl File {
|
|||
///
|
||||
/// Note that some platforms may simply implement this in terms of
|
||||
/// `sync_all`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
/// use std::io::prelude::*;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// let mut f = try!(File::create("foo.txt"));
|
||||
/// try!(f.write_all(b"Hello, world!"));
|
||||
///
|
||||
/// try!(f.sync_data());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn sync_data(&self) -> io::Result<()> {
|
||||
self.inner.datasync()
|
||||
|
@ -182,12 +234,36 @@ impl File {
|
|||
/// be shrunk. If it is greater than the current file's size, then the file
|
||||
/// will be extended to `size` and have all of the intermediate data filled
|
||||
/// in with 0s.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// let mut f = try!(File::open("foo.txt"));
|
||||
/// try!(f.set_len(0));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn set_len(&self, size: u64) -> io::Result<()> {
|
||||
self.inner.truncate(size)
|
||||
}
|
||||
|
||||
/// Queries metadata about the underlying file.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use std::fs::File;
|
||||
///
|
||||
/// # fn foo() -> std::io::Result<()> {
|
||||
/// let mut f = try!(File::open("foo.txt"));
|
||||
/// let metadata = try!(f.metadata());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn metadata(&self) -> io::Result<Metadata> {
|
||||
self.inner.file_attr().map(Metadata)
|
||||
|
|
|
@ -120,7 +120,7 @@ impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug {
|
|||
///
|
||||
/// The buffer will be written out when the writer is dropped.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct BufWriter<W> {
|
||||
pub struct BufWriter<W: Write> {
|
||||
inner: Option<W>,
|
||||
buf: Vec<u8>,
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ impl<W: Write> Write for BufWriter<W> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W> fmt::Debug for BufWriter<W> where W: fmt::Debug {
|
||||
impl<W: Write> fmt::Debug for BufWriter<W> where W: fmt::Debug {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "BufWriter {{ writer: {:?}, buffer: {}/{} }}",
|
||||
self.inner.as_ref().unwrap(), self.buf.len(), self.buf.capacity())
|
||||
|
@ -276,7 +276,7 @@ impl<W> fmt::Display for IntoInnerError<W> {
|
|||
///
|
||||
/// The buffer will be written out when the writer is dropped.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct LineWriter<W> {
|
||||
pub struct LineWriter<W: Write> {
|
||||
inner: BufWriter<W>,
|
||||
}
|
||||
|
||||
|
@ -335,7 +335,7 @@ impl<W: Write> Write for LineWriter<W> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W> fmt::Debug for LineWriter<W> where W: fmt::Debug {
|
||||
impl<W: Write> fmt::Debug for LineWriter<W> where W: fmt::Debug {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "LineWriter {{ writer: {:?}, buffer: {}/{} }}",
|
||||
self.inner.inner, self.inner.buf.len(),
|
||||
|
@ -343,16 +343,16 @@ impl<W> fmt::Debug for LineWriter<W> where W: fmt::Debug {
|
|||
}
|
||||
}
|
||||
|
||||
struct InternalBufWriter<W>(BufWriter<W>);
|
||||
struct InternalBufWriter<W: Write>(BufWriter<W>);
|
||||
|
||||
impl<W> InternalBufWriter<W> {
|
||||
impl<W: Read + Write> InternalBufWriter<W> {
|
||||
fn get_mut(&mut self) -> &mut BufWriter<W> {
|
||||
let InternalBufWriter(ref mut w) = *self;
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Read> Read for InternalBufWriter<W> {
|
||||
impl<W: Read + Write> Read for InternalBufWriter<W> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
self.get_mut().inner.as_mut().unwrap().read(buf)
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ impl<W: Read> Read for InternalBufWriter<W> {
|
|||
///
|
||||
/// The output buffer will be written out when this stream is dropped.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct BufStream<S> {
|
||||
pub struct BufStream<S: Write> {
|
||||
inner: BufReader<InternalBufWriter<S>>
|
||||
}
|
||||
|
||||
|
@ -448,7 +448,7 @@ impl<S: Read + Write> Write for BufStream<S> {
|
|||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<S> fmt::Debug for BufStream<S> where S: fmt::Debug {
|
||||
impl<S: Write> fmt::Debug for BufStream<S> where S: fmt::Debug {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let reader = &self.inner;
|
||||
let writer = &self.inner.inner.0;
|
||||
|
|
|
@ -35,25 +35,33 @@ impl<T: Send + Sync + 'static> Lazy<T> {
|
|||
pub fn get(&'static self) -> Option<Arc<T>> {
|
||||
let _g = self.lock.lock();
|
||||
unsafe {
|
||||
let mut ptr = *self.ptr.get();
|
||||
let ptr = *self.ptr.get();
|
||||
if ptr.is_null() {
|
||||
ptr = boxed::into_raw(self.init());
|
||||
*self.ptr.get() = ptr;
|
||||
Some(self.init())
|
||||
} else if ptr as usize == 1 {
|
||||
return None
|
||||
None
|
||||
} else {
|
||||
Some((*ptr).clone())
|
||||
}
|
||||
Some((*ptr).clone())
|
||||
}
|
||||
}
|
||||
|
||||
fn init(&'static self) -> Box<Arc<T>> {
|
||||
rt::at_exit(move || unsafe {
|
||||
unsafe fn init(&'static self) -> Arc<T> {
|
||||
// If we successfully register an at exit handler, then we cache the
|
||||
// `Arc` allocation in our own internal box (it will get deallocated by
|
||||
// the at exit handler). Otherwise we just return the freshly allocated
|
||||
// `Arc`.
|
||||
let registered = rt::at_exit(move || {
|
||||
let g = self.lock.lock();
|
||||
let ptr = *self.ptr.get();
|
||||
*self.ptr.get() = 1 as *mut _;
|
||||
drop(g);
|
||||
drop(Box::from_raw(ptr))
|
||||
});
|
||||
Box::new((self.init)())
|
||||
let ret = (self.init)();
|
||||
if registered.is_ok() {
|
||||
*self.ptr.get() = boxed::into_raw(Box::new(ret.clone()));
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,12 @@ use cmp;
|
|||
use unicode::str as core_str;
|
||||
use error as std_error;
|
||||
use fmt;
|
||||
use iter::Iterator;
|
||||
use iter::{self, Iterator, IteratorExt, Extend};
|
||||
use marker::Sized;
|
||||
use ops::{Drop, FnOnce};
|
||||
use option::Option::{self, Some, None};
|
||||
use result::Result::{Ok, Err};
|
||||
use result;
|
||||
use slice;
|
||||
use string::String;
|
||||
use str;
|
||||
use vec::Vec;
|
||||
|
@ -50,41 +49,26 @@ mod stdio;
|
|||
const DEFAULT_BUF_SIZE: usize = 64 * 1024;
|
||||
|
||||
// Acquires a slice of the vector `v` from its length to its capacity
|
||||
// (uninitialized data), reads into it, and then updates the length.
|
||||
// (after initializing the data), reads into it, and then updates the length.
|
||||
//
|
||||
// This function is leveraged to efficiently read some bytes into a destination
|
||||
// vector without extra copying and taking advantage of the space that's already
|
||||
// in `v`.
|
||||
//
|
||||
// The buffer we're passing down, however, is pointing at uninitialized data
|
||||
// (the end of a `Vec`), and many operations will be *much* faster if we don't
|
||||
// have to zero it out. In order to prevent LLVM from generating an `undef`
|
||||
// value when reads happen from this uninitialized memory, we force LLVM to
|
||||
// think it's initialized by sending it through a black box. This should prevent
|
||||
// actual undefined behavior after optimizations.
|
||||
fn with_end_to_cap<F>(v: &mut Vec<u8>, f: F) -> Result<usize>
|
||||
where F: FnOnce(&mut [u8]) -> Result<usize>
|
||||
{
|
||||
unsafe {
|
||||
let n = try!(f({
|
||||
let base = v.as_mut_ptr().offset(v.len() as isize);
|
||||
black_box(slice::from_raw_parts_mut(base,
|
||||
v.capacity() - v.len()))
|
||||
}));
|
||||
|
||||
// If the closure (typically a `read` implementation) reported that it
|
||||
// read a larger number of bytes than the vector actually has, we need
|
||||
// to be sure to clamp the vector to at most its capacity.
|
||||
let new_len = cmp::min(v.capacity(), v.len() + n);
|
||||
v.set_len(new_len);
|
||||
return Ok(n);
|
||||
}
|
||||
|
||||
// Semi-hack used to prevent LLVM from retaining any assumptions about
|
||||
// `dummy` over this function call
|
||||
unsafe fn black_box<T>(mut dummy: T) -> T {
|
||||
asm!("" :: "r"(&mut dummy) : "memory");
|
||||
dummy
|
||||
let len = v.len();
|
||||
let new_area = v.capacity() - len;
|
||||
v.extend(iter::repeat(0).take(new_area));
|
||||
match f(&mut v[len..]) {
|
||||
Ok(n) => {
|
||||
v.truncate(len + n);
|
||||
Ok(n)
|
||||
}
|
||||
Err(e) => {
|
||||
v.truncate(len);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -135,6 +135,8 @@
|
|||
#![feature(no_std)]
|
||||
#![no_std]
|
||||
|
||||
#![allow(trivial_casts)]
|
||||
#![allow(trivial_numeric_casts)]
|
||||
#![deny(missing_docs)]
|
||||
|
||||
#[cfg(test)] extern crate test;
|
||||
|
|
|
@ -148,14 +148,14 @@ impl<R: Reader> Reader for BufferedReader<R> {
|
|||
/// writer.write_str("hello, world").unwrap();
|
||||
/// writer.flush().unwrap();
|
||||
/// ```
|
||||
pub struct BufferedWriter<W> {
|
||||
pub struct BufferedWriter<W: Writer> {
|
||||
inner: Option<W>,
|
||||
buf: Vec<u8>,
|
||||
pos: uint
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W> fmt::Debug for BufferedWriter<W> where W: fmt::Debug {
|
||||
impl<W: Writer> fmt::Debug for BufferedWriter<W> where W: fmt::Debug {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "BufferedWriter {{ writer: {:?}, buffer: {}/{} }}",
|
||||
self.inner.as_ref().unwrap(), self.pos, self.buf.len())
|
||||
|
@ -250,12 +250,12 @@ impl<W: Writer> Drop for BufferedWriter<W> {
|
|||
/// `'\n'`) is detected.
|
||||
///
|
||||
/// This writer will be flushed when it is dropped.
|
||||
pub struct LineBufferedWriter<W> {
|
||||
pub struct LineBufferedWriter<W: Writer> {
|
||||
inner: BufferedWriter<W>,
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<W> fmt::Debug for LineBufferedWriter<W> where W: fmt::Debug {
|
||||
impl<W: Writer> fmt::Debug for LineBufferedWriter<W> where W: fmt::Debug {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(fmt, "LineBufferedWriter {{ writer: {:?}, buffer: {}/{} }}",
|
||||
self.inner.inner, self.inner.pos, self.inner.buf.len())
|
||||
|
@ -299,16 +299,16 @@ impl<W: Writer> Writer for LineBufferedWriter<W> {
|
|||
fn flush(&mut self) -> IoResult<()> { self.inner.flush() }
|
||||
}
|
||||
|
||||
struct InternalBufferedWriter<W>(BufferedWriter<W>);
|
||||
struct InternalBufferedWriter<W: Writer>(BufferedWriter<W>);
|
||||
|
||||
impl<W> InternalBufferedWriter<W> {
|
||||
impl<W: Writer> InternalBufferedWriter<W> {
|
||||
fn get_mut<'a>(&'a mut self) -> &'a mut BufferedWriter<W> {
|
||||
let InternalBufferedWriter(ref mut w) = *self;
|
||||
return w;
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Reader> Reader for InternalBufferedWriter<W> {
|
||||
impl<W: Reader + Writer> Reader for InternalBufferedWriter<W> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
|
||||
self.get_mut().inner.as_mut().unwrap().read(buf)
|
||||
}
|
||||
|
@ -343,12 +343,12 @@ impl<W: Reader> Reader for InternalBufferedWriter<W> {
|
|||
/// Err(e) => println!("error reading: {}", e)
|
||||
/// }
|
||||
/// ```
|
||||
pub struct BufferedStream<S> {
|
||||
pub struct BufferedStream<S: Writer> {
|
||||
inner: BufferedReader<InternalBufferedWriter<S>>
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<S> fmt::Debug for BufferedStream<S> where S: fmt::Debug {
|
||||
impl<S: Writer> fmt::Debug for BufferedStream<S> where S: fmt::Debug {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
let reader = &self.inner;
|
||||
let writer = &self.inner.inner.0;
|
||||
|
|
|
@ -240,7 +240,7 @@ pub fn stdin() -> StdinReader {
|
|||
STDIN = boxed::into_raw(box stdin);
|
||||
|
||||
// Make sure to free it at exit
|
||||
rt::at_exit(|| {
|
||||
let _ = rt::at_exit(|| {
|
||||
Box::from_raw(STDIN);
|
||||
STDIN = ptr::null_mut();
|
||||
});
|
||||
|
@ -337,10 +337,10 @@ pub fn set_stderr(_stderr: Box<Writer + Send>) -> Option<Box<Writer + Send>> {
|
|||
// })
|
||||
// })
|
||||
fn with_task_stdout<F>(f: F) where F: FnOnce(&mut Writer) -> IoResult<()> {
|
||||
let mut my_stdout = LOCAL_STDOUT.with(|slot| {
|
||||
let mut my_stdout: Box<Writer + Send> = LOCAL_STDOUT.with(|slot| {
|
||||
slot.borrow_mut().take()
|
||||
}).unwrap_or_else(|| {
|
||||
box stdout() as Box<Writer + Send>
|
||||
box stdout()
|
||||
});
|
||||
let result = f(&mut *my_stdout);
|
||||
let mut var = Some(my_stdout);
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
//!
|
||||
//! Documentation can be found on the `rt::at_exit` function.
|
||||
|
||||
// FIXME: switch this to use atexit. Currently this
|
||||
// segfaults (the queue's memory is mysteriously gone), so
|
||||
// instead the cleanup is tied to the `std::rt` entry point.
|
||||
|
||||
use boxed;
|
||||
use boxed::Box;
|
||||
use vec::Vec;
|
||||
|
@ -27,47 +31,56 @@ type Queue = Vec<Thunk<'static>>;
|
|||
static LOCK: Mutex = MUTEX_INIT;
|
||||
static mut QUEUE: *mut Queue = 0 as *mut Queue;
|
||||
|
||||
unsafe fn init() {
|
||||
// The maximum number of times the cleanup routines will be run. While running
|
||||
// the at_exit closures new ones may be registered, and this count is the number
|
||||
// of times the new closures will be allowed to register successfully. After
|
||||
// this number of iterations all new registrations will return `false`.
|
||||
const ITERS: usize = 10;
|
||||
|
||||
unsafe fn init() -> bool {
|
||||
if QUEUE.is_null() {
|
||||
let state: Box<Queue> = box Vec::new();
|
||||
QUEUE = boxed::into_raw(state);
|
||||
} else {
|
||||
} else if QUEUE as usize == 1 {
|
||||
// can't re-init after a cleanup
|
||||
rtassert!(QUEUE as uint != 1);
|
||||
return false
|
||||
}
|
||||
|
||||
// FIXME: switch this to use atexit as below. Currently this
|
||||
// segfaults (the queue's memory is mysteriously gone), so
|
||||
// instead the cleanup is tied to the `std::rt` entry point.
|
||||
//
|
||||
// ::libc::atexit(cleanup);
|
||||
return true
|
||||
}
|
||||
|
||||
pub fn cleanup() {
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
let queue = QUEUE;
|
||||
QUEUE = 1 as *mut _;
|
||||
LOCK.unlock();
|
||||
for i in 0..ITERS {
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
let queue = QUEUE;
|
||||
QUEUE = if i == ITERS - 1 {1} else {0} as *mut _;
|
||||
LOCK.unlock();
|
||||
|
||||
// make sure we're not recursively cleaning up
|
||||
rtassert!(queue as uint != 1);
|
||||
// make sure we're not recursively cleaning up
|
||||
rtassert!(queue as usize != 1);
|
||||
|
||||
// If we never called init, not need to cleanup!
|
||||
if queue as uint != 0 {
|
||||
let queue: Box<Queue> = Box::from_raw(queue);
|
||||
for to_run in *queue {
|
||||
to_run.invoke(());
|
||||
// If we never called init, not need to cleanup!
|
||||
if queue as usize != 0 {
|
||||
let queue: Box<Queue> = Box::from_raw(queue);
|
||||
for to_run in *queue {
|
||||
to_run.invoke(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(f: Thunk<'static>) {
|
||||
pub fn push(f: Thunk<'static>) -> bool {
|
||||
let mut ret = true;
|
||||
unsafe {
|
||||
LOCK.lock();
|
||||
init();
|
||||
(*QUEUE).push(f);
|
||||
if init() {
|
||||
(*QUEUE).push(f);
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
LOCK.unlock();
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
|
|
@ -17,14 +17,9 @@
|
|||
//! time being.
|
||||
|
||||
#![unstable(feature = "std_misc")]
|
||||
|
||||
// FIXME: this should not be here.
|
||||
#![allow(missing_docs)]
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use marker::Send;
|
||||
use ops::FnOnce;
|
||||
use prelude::v1::*;
|
||||
use sys;
|
||||
use thunk::Thunk;
|
||||
use usize;
|
||||
|
@ -73,7 +68,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
|
|||
use thread::Thread;
|
||||
|
||||
let something_around_the_top_of_the_stack = 1;
|
||||
let addr = &something_around_the_top_of_the_stack as *const int;
|
||||
let addr = &something_around_the_top_of_the_stack as *const _ as *const int;
|
||||
let my_stack_top = addr as uint;
|
||||
|
||||
// FIXME #11359 we just assume that this thread has a stack of a
|
||||
|
@ -149,13 +144,16 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int {
|
|||
|
||||
/// Enqueues a procedure to run when the main thread exits.
|
||||
///
|
||||
/// It is forbidden for procedures to register more `at_exit` handlers when they
|
||||
/// are running, and doing so will lead to a process abort.
|
||||
/// Currently these closures are only run once the main *Rust* thread exits.
|
||||
/// Once the `at_exit` handlers begin running, more may be enqueued, but not
|
||||
/// infinitely so. Eventually a handler registration will be forced to fail.
|
||||
///
|
||||
/// Note that other threads may still be running when `at_exit` routines start
|
||||
/// running.
|
||||
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) {
|
||||
at_exit_imp::push(Thunk::new(f));
|
||||
/// Returns `Ok` if the handler was successfully registered, meaning that the
|
||||
/// closure will be run once the main thread exits. Returns `Err` to indicate
|
||||
/// that the closure could not be registered, meaning that it is not scheduled
|
||||
/// to be rune.
|
||||
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> {
|
||||
if at_exit_imp::push(Thunk::new(f)) {Ok(())} else {Err(())}
|
||||
}
|
||||
|
||||
/// One-time runtime cleanup.
|
||||
|
|
|
@ -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<T> {
|
||||
pub struct Receiver<T:Send> {
|
||||
inner: UnsafeCell<Flavor<T>>,
|
||||
}
|
||||
|
||||
|
@ -354,14 +354,14 @@ unsafe impl<T: Send> Send for Receiver<T> { }
|
|||
/// 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:'a> {
|
||||
pub struct Iter<'a, T:Send+'a> {
|
||||
rx: &'a Receiver<T>
|
||||
}
|
||||
|
||||
/// 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<T> {
|
||||
pub struct Sender<T:Send> {
|
||||
inner: UnsafeCell<Flavor<T>>,
|
||||
}
|
||||
|
||||
|
@ -372,7 +372,7 @@ unsafe impl<T: Send> Send for Sender<T> { }
|
|||
/// The sending-half of Rust's synchronous channel type. This half can only be
|
||||
/// owned by one task, but it can be cloned to send to other tasks.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct SyncSender<T> {
|
||||
pub struct SyncSender<T: Send> {
|
||||
inner: Arc<UnsafeCell<sync::Packet<T>>>,
|
||||
}
|
||||
|
||||
|
@ -433,7 +433,7 @@ pub enum TrySendError<T> {
|
|||
Disconnected(T),
|
||||
}
|
||||
|
||||
enum Flavor<T> {
|
||||
enum Flavor<T:Send> {
|
||||
Oneshot(Arc<UnsafeCell<oneshot::Packet<T>>>),
|
||||
Stream(Arc<UnsafeCell<stream::Packet<T>>>),
|
||||
Shared(Arc<UnsafeCell<shared::Packet<T>>>),
|
||||
|
@ -441,7 +441,7 @@ enum Flavor<T> {
|
|||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
trait UnsafeFlavor<T> {
|
||||
trait UnsafeFlavor<T:Send> {
|
||||
fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell<Flavor<T>>;
|
||||
unsafe fn inner_mut<'a>(&'a self) -> &'a mut Flavor<T> {
|
||||
&mut *self.inner_unsafe().get()
|
||||
|
@ -450,12 +450,12 @@ trait UnsafeFlavor<T> {
|
|||
&*self.inner_unsafe().get()
|
||||
}
|
||||
}
|
||||
impl<T> UnsafeFlavor<T> for Sender<T> {
|
||||
impl<T:Send> UnsafeFlavor<T> for Sender<T> {
|
||||
fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell<Flavor<T>> {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
impl<T> UnsafeFlavor<T> for Receiver<T> {
|
||||
impl<T:Send> UnsafeFlavor<T> for Receiver<T> {
|
||||
fn inner_unsafe<'a>(&'a self) -> &'a UnsafeCell<Flavor<T>> {
|
||||
&self.inner
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ struct Node<T> {
|
|||
/// 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<T> {
|
||||
pub struct Queue<T: Send> {
|
||||
head: AtomicPtr<Node<T>>,
|
||||
tail: UnsafeCell<*mut Node<T>>,
|
||||
}
|
||||
|
|
|
@ -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<T> {
|
||||
pub struct Packet<T:Send> {
|
||||
// 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<T> {
|
|||
upgrade: MyUpgrade<T>,
|
||||
}
|
||||
|
||||
pub enum Failure<T> {
|
||||
pub enum Failure<T:Send> {
|
||||
Empty,
|
||||
Disconnected,
|
||||
Upgraded(Receiver<T>),
|
||||
|
@ -76,13 +76,13 @@ pub enum UpgradeResult {
|
|||
UpWoke(SignalToken),
|
||||
}
|
||||
|
||||
pub enum SelectionResult<T> {
|
||||
pub enum SelectionResult<T:Send> {
|
||||
SelCanceled,
|
||||
SelUpgraded(SignalToken, Receiver<T>),
|
||||
SelSuccess,
|
||||
}
|
||||
|
||||
enum MyUpgrade<T> {
|
||||
enum MyUpgrade<T:Send> {
|
||||
NothingSent,
|
||||
SendUsed,
|
||||
GoUp(Receiver<T>),
|
||||
|
|
|
@ -80,7 +80,7 @@ impl !marker::Send for Select {}
|
|||
/// A handle to a receiver which is currently a member of a `Select` set of
|
||||
/// receivers. This handle is used to keep the receiver in the set as well as
|
||||
/// interact with the underlying receiver.
|
||||
pub struct Handle<'rx, T:'rx> {
|
||||
pub struct Handle<'rx, T:Send+'rx> {
|
||||
/// The ID of this handle, used to compare against the return value of
|
||||
/// `Select::wait()`
|
||||
id: usize,
|
||||
|
|
|
@ -40,7 +40,7 @@ const MAX_STEALS: isize = 5;
|
|||
#[cfg(not(test))]
|
||||
const MAX_STEALS: isize = 1 << 20;
|
||||
|
||||
pub struct Packet<T> {
|
||||
pub struct Packet<T: Send> {
|
||||
queue: mpsc::Queue<T>,
|
||||
cnt: AtomicIsize, // How many items are on this channel
|
||||
steals: isize, // How many times has a port received without blocking?
|
||||
|
|
|
@ -57,7 +57,7 @@ struct Node<T> {
|
|||
/// 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<T> {
|
||||
pub struct Queue<T: Send> {
|
||||
// consumer fields
|
||||
tail: UnsafeCell<*mut Node<T>>, // where to pop from
|
||||
tail_prev: AtomicPtr<Node<T>>, // where to pop from
|
||||
|
|
|
@ -39,7 +39,7 @@ const MAX_STEALS: isize = 5;
|
|||
#[cfg(not(test))]
|
||||
const MAX_STEALS: isize = 1 << 20;
|
||||
|
||||
pub struct Packet<T> {
|
||||
pub struct Packet<T:Send> {
|
||||
queue: spsc::Queue<Message<T>>, // internal queue for all message
|
||||
|
||||
cnt: AtomicIsize, // How many items are on this channel
|
||||
|
@ -49,7 +49,7 @@ pub struct Packet<T> {
|
|||
port_dropped: AtomicBool, // flag if the channel has been destroyed.
|
||||
}
|
||||
|
||||
pub enum Failure<T> {
|
||||
pub enum Failure<T:Send> {
|
||||
Empty,
|
||||
Disconnected,
|
||||
Upgraded(Receiver<T>),
|
||||
|
@ -61,7 +61,7 @@ pub enum UpgradeResult {
|
|||
UpWoke(SignalToken),
|
||||
}
|
||||
|
||||
pub enum SelectionResult<T> {
|
||||
pub enum SelectionResult<T:Send> {
|
||||
SelSuccess,
|
||||
SelCanceled,
|
||||
SelUpgraded(SignalToken, Receiver<T>),
|
||||
|
@ -69,7 +69,7 @@ pub enum SelectionResult<T> {
|
|||
|
||||
// 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<T>
|
||||
enum Message<T> {
|
||||
enum Message<T:Send> {
|
||||
Data(T),
|
||||
GoUp(Receiver<T>),
|
||||
}
|
||||
|
|
|
@ -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<T> {
|
||||
pub struct Packet<T: Send> {
|
||||
/// Only field outside of the mutex. Just done for kicks, but mainly because
|
||||
/// the other shared channel already had the code implemented
|
||||
channels: AtomicUsize,
|
||||
|
|
|
@ -112,7 +112,7 @@ use fmt;
|
|||
/// *guard += 1;
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct Mutex<T> {
|
||||
pub struct Mutex<T: Send> {
|
||||
// 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
|
||||
|
@ -366,7 +366,7 @@ mod test {
|
|||
use sync::{Arc, Mutex, StaticMutex, MUTEX_INIT, Condvar};
|
||||
use thread;
|
||||
|
||||
struct Packet<T>(Arc<(Mutex<T>, Condvar)>);
|
||||
struct Packet<T: Send>(Arc<(Mutex<T>, Condvar)>);
|
||||
|
||||
unsafe impl<T: Send> Send for Packet<T> {}
|
||||
unsafe impl<T> Sync for Packet<T> {}
|
||||
|
|
|
@ -38,7 +38,7 @@ use thread;
|
|||
///
|
||||
/// The fields of this helper are all public, but they should not be used, this
|
||||
/// is for static initialization.
|
||||
pub struct Helper<M> {
|
||||
pub struct Helper<M:Send> {
|
||||
/// Internal lock which protects the remaining fields
|
||||
pub lock: StaticMutex,
|
||||
pub cond: StaticCondvar,
|
||||
|
@ -112,7 +112,7 @@ impl<M: Send> Helper<M> {
|
|||
self.cond.notify_one()
|
||||
});
|
||||
|
||||
rt::at_exit(move || { self.shutdown() });
|
||||
let _ = rt::at_exit(move || { self.shutdown() });
|
||||
*self.initialized.get() = true;
|
||||
} else if *self.chan.get() as uint == 1 {
|
||||
panic!("cannot continue usage after shutdown");
|
||||
|
|
|
@ -36,7 +36,7 @@ pub fn init() {
|
|||
&mut data);
|
||||
assert_eq!(ret, 0);
|
||||
|
||||
rt::at_exit(|| { c::WSACleanup(); })
|
||||
let _ = rt::at_exit(|| { c::WSACleanup(); });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,7 @@ impl Iterator for Env {
|
|||
if *self.cur == 0 { return None }
|
||||
let p = &*self.cur;
|
||||
let mut len = 0;
|
||||
while *(p as *const _).offset(len) != 0 {
|
||||
while *(p as *const u16).offset(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
let p = p as *const u16;
|
||||
|
|
|
@ -133,9 +133,8 @@ unsafe fn init_dtors() {
|
|||
if !DTORS.is_null() { return }
|
||||
|
||||
let dtors = box Vec::<(Key, Dtor)>::new();
|
||||
DTORS = boxed::into_raw(dtors);
|
||||
|
||||
rt::at_exit(move|| {
|
||||
let res = rt::at_exit(move|| {
|
||||
DTOR_LOCK.lock();
|
||||
let dtors = DTORS;
|
||||
DTORS = 1 as *mut _;
|
||||
|
@ -143,6 +142,11 @@ unsafe fn init_dtors() {
|
|||
assert!(DTORS as uint == 1); // can't re-init after destructing
|
||||
DTOR_LOCK.unlock();
|
||||
});
|
||||
if res.is_ok() {
|
||||
DTORS = boxed::into_raw(dtors);
|
||||
} else {
|
||||
DTORS = 1 as *mut _;
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn register_dtor(key: Key, dtor: Dtor) {
|
||||
|
|
|
@ -176,6 +176,7 @@ macro_rules! __thread_local_inner {
|
|||
}
|
||||
};
|
||||
|
||||
#[allow(trivial_casts)]
|
||||
#[cfg(any(not(any(target_os = "macos", target_os = "linux")), target_arch = "aarch64"))]
|
||||
const _INIT: ::std::thread::__local::__impl::KeyInner<$t> = {
|
||||
::std::thread::__local::__impl::KeyInner {
|
||||
|
|
|
@ -698,7 +698,7 @@ impl Drop for JoinHandle {
|
|||
/// permission.
|
||||
#[must_use = "thread will be immediately joined if `JoinGuard` is not used"]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub struct JoinGuard<'a, T: 'a> {
|
||||
pub struct JoinGuard<'a, T: Send + 'a> {
|
||||
inner: JoinInner<T>,
|
||||
_marker: PhantomData<&'a T>,
|
||||
}
|
||||
|
|
|
@ -284,7 +284,7 @@ pub const COMMAND_LINE_EXPN: ExpnId = ExpnId(-2);
|
|||
|
||||
impl ExpnId {
|
||||
pub fn from_llvm_cookie(cookie: c_uint) -> ExpnId {
|
||||
ExpnId(cookie as u32)
|
||||
ExpnId(cookie)
|
||||
}
|
||||
|
||||
pub fn to_llvm_cookie(self) -> i32 {
|
||||
|
@ -376,7 +376,7 @@ impl Encodable for FileMap {
|
|||
match bytes_per_diff {
|
||||
1 => for diff in diff_iter { try! { (diff.0 as u8).encode(s) } },
|
||||
2 => for diff in diff_iter { try! { (diff.0 as u16).encode(s) } },
|
||||
4 => for diff in diff_iter { try! { (diff.0 as u32).encode(s) } },
|
||||
4 => for diff in diff_iter { try! { diff.0.encode(s) } },
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
|
@ -650,7 +650,7 @@ impl CodeMap {
|
|||
let lo = self.lookup_char_pos(sp.lo);
|
||||
let hi = self.lookup_char_pos(sp.hi);
|
||||
let mut lines = Vec::new();
|
||||
for i in lo.line - 1..hi.line as usize {
|
||||
for i in lo.line - 1..hi.line {
|
||||
lines.push(i);
|
||||
};
|
||||
FileLines {file: lo.file, lines: lines}
|
||||
|
|
|
@ -264,7 +264,7 @@ macro_rules! make_MacEager {
|
|||
box MacEager {
|
||||
$fld: Some(v),
|
||||
..Default::default()
|
||||
} as Box<MacResult>
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ impl DummyResult {
|
|||
/// Use this as a return value after hitting any errors and
|
||||
/// calling `span_err`.
|
||||
pub fn any(sp: Span) -> Box<MacResult+'static> {
|
||||
box DummyResult { expr_only: false, span: sp } as Box<MacResult+'static>
|
||||
box DummyResult { expr_only: false, span: sp }
|
||||
}
|
||||
|
||||
/// Create a default MacResult that can only be an expression.
|
||||
|
@ -339,7 +339,7 @@ impl DummyResult {
|
|||
/// if an error is encountered internally, the user will receive
|
||||
/// an error that they also used it in the wrong place.
|
||||
pub fn expr(sp: Span) -> Box<MacResult+'static> {
|
||||
box DummyResult { expr_only: true, span: sp } as Box<MacResult+'static>
|
||||
box DummyResult { expr_only: true, span: sp }
|
||||
}
|
||||
|
||||
/// A plain dummy expression.
|
||||
|
|
|
@ -262,6 +262,7 @@ pub mod rt {
|
|||
(unsigned, $t:ty, $tag:expr) => (
|
||||
impl ToSource for $t {
|
||||
fn to_source(&self) -> String {
|
||||
#![allow(trivial_numeric_casts)]
|
||||
let lit = ast::LitInt(*self as u64, ast::UnsignedIntLit($tag));
|
||||
pprust::lit_to_string(&dummy_spanned(lit))
|
||||
}
|
||||
|
|
|
@ -169,7 +169,7 @@ fn generic_extension<'cx>(cx: &'cx ExtCtxt,
|
|||
// Weird, but useful for X-macros.
|
||||
return box ParserAnyMacro {
|
||||
parser: RefCell::new(p),
|
||||
} as Box<MacResult+'cx>
|
||||
}
|
||||
}
|
||||
Failure(sp, ref msg) => if sp.lo >= best_fail_spot.lo {
|
||||
best_fail_spot = sp;
|
||||
|
|
|
@ -758,7 +758,7 @@ impl<'a> StringReader<'a> {
|
|||
self.err_span_char(self.last_pos, self.pos,
|
||||
"illegal character in numeric character escape", c);
|
||||
0
|
||||
}) as u32;
|
||||
});
|
||||
self.bump();
|
||||
}
|
||||
|
||||
|
@ -887,7 +887,7 @@ impl<'a> StringReader<'a> {
|
|||
self.fatal_span_char(self.last_pos, self.pos,
|
||||
"illegal character in unicode escape", c);
|
||||
}
|
||||
}) as u32;
|
||||
});
|
||||
self.bump();
|
||||
count += 1;
|
||||
}
|
||||
|
|
|
@ -865,7 +865,7 @@ impl<'a> Parser<'a> {
|
|||
} else {
|
||||
// Avoid token copies with `replace`.
|
||||
let buffer_start = self.buffer_start as usize;
|
||||
let next_index = (buffer_start + 1) & 3 as usize;
|
||||
let next_index = (buffer_start + 1) & 3;
|
||||
self.buffer_start = next_index as isize;
|
||||
|
||||
let placeholder = TokenAndSpan {
|
||||
|
|
|
@ -2836,7 +2836,7 @@ impl<'a> State<'a> {
|
|||
ast::LitBinary(ref v) => {
|
||||
let mut escaped: String = String::new();
|
||||
for &ch in &**v {
|
||||
escaped.extend(ascii::escape_default(ch as u8)
|
||||
escaped.extend(ascii::escape_default(ch)
|
||||
.map(|c| c as char));
|
||||
}
|
||||
word(&mut self.s, &format!("b\"{}\"", escaped))
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue