Auto merge of #23681 - alexcrichton:rollup, r=alexcrichton

This commit is contained in:
bors 2015-03-25 01:42:42 +00:00
commit 593db005d4
171 changed files with 2213 additions and 1035 deletions

View file

@ -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 twos 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

View file

@ -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)

View 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
Theres 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>;
```
Youll 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 cant create a trait object like this, becuase we dont 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 didnt proide this constraint, we
couldnt be sure which `impl` to match this trait object to.

View file

@ -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

View file

@ -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) {

View file

@ -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

View file

@ -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.

View file

@ -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;

View file

@ -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)]

View file

@ -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);

View file

@ -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,

View file

@ -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`

View file

@ -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
///

View file

@ -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;

View file

@ -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)
}
}

View file

@ -13,6 +13,7 @@
// FIXME: #6220 Implement floating point formatting
#![allow(unsigned_negation)]
#![allow(trivial_numeric_casts)]
use fmt;
use iter::IteratorExt;

View file

@ -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) })

View file

@ -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)
}

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i16")]
#![allow(trivial_numeric_casts)]
int_module! { i16, 16 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i32")]
#![allow(trivial_numeric_casts)]
int_module! { i32, 32 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i64")]
#![allow(trivial_numeric_casts)]
int_module! { i64, 64 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "i8")]
#![allow(trivial_numeric_casts)]
int_module! { i8, 8 }

View file

@ -9,6 +9,7 @@
// except according to those terms.
#![doc(hidden)]
#![allow(trivial_numeric_casts)]
macro_rules! int_module { ($T:ty, $bits:expr) => (

View file

@ -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 }

View file

@ -14,6 +14,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)]
#![allow(trivial_numeric_casts)]
use self::wrapping::{OverflowingOps, WrappingOps};

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u16")]
#![allow(trivial_numeric_casts)]
uint_module! { u16, i16, 16 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u32")]
#![allow(trivial_numeric_casts)]
uint_module! { u32, i32, 32 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u64")]
#![allow(trivial_numeric_casts)]
uint_module! { u64, i64, 64 }

View file

@ -12,5 +12,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "u8")]
#![allow(trivial_numeric_casts)]
uint_module! { u8, i8, 8 }

View file

@ -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) => (

View file

@ -16,5 +16,6 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(primitive = "usize")]
#![allow(trivial_numeric_casts)]
uint_module! { usize, isize, ::isize::BITS }

View file

@ -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>
{

View file

@ -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.

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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};

View file

@ -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();

View file

@ -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 {

View file

@ -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;

View file

@ -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
)
}
}

View file

@ -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)

View file

@ -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)

View file

@ -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);

View file

@ -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(());
}

View file

@ -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
}

View file

@ -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;

View file

@ -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");

View file

@ -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")]

View file

@ -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;

View file

@ -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
}

View file

@ -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
}

View file

@ -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,

View file

@ -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);
}

View file

@ -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> {

View file

@ -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));

View file

@ -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>(

View file

@ -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,

View file

@ -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),

View file

@ -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,

View file

@ -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;
}

View file

@ -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);

View file

@ -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

View file

@ -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,

View file

@ -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 }

View file

@ -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(),

View file

@ -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)
}
})+
)
}

View file

@ -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)

View file

@ -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;

View file

@ -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
}
}

View file

@ -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)
}
}
}

View file

@ -135,6 +135,8 @@
#![feature(no_std)]
#![no_std]
#![allow(trivial_casts)]
#![allow(trivial_numeric_casts)]
#![deny(missing_docs)]
#[cfg(test)] extern crate test;

View file

@ -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;

View file

@ -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);

View file

@ -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
}

View file

@ -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.

View file

@ -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
}

View file

@ -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>>,
}

View file

@ -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>),

View file

@ -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,

View file

@ -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?

View file

@ -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

View file

@ -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>),
}

View file

@ -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,

View file

@ -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> {}

View file

@ -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");

View file

@ -36,7 +36,7 @@ pub fn init() {
&mut data);
assert_eq!(ret, 0);
rt::at_exit(|| { c::WSACleanup(); })
let _ = rt::at_exit(|| { c::WSACleanup(); });
});
}

View file

@ -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;

View file

@ -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) {

View file

@ -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 {

View file

@ -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>,
}

View file

@ -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}

View file

@ -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.

View file

@ -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))
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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 {

View file

@ -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