auto merge of #14397 : nick29581/rust/coerce, r=pnkfelix
DST coercions and DST fields in structs The commits are not quite stand alone, I should probably squash them together before landing. In particular if you review the individual commits, then you'll see some scrappy stuff that gets fixed in later commits. But reading the commits in order might be easier to get an overall idea of what is going on. The first commit includes putting back time zone into our time library - @pcwalton removed that as part of his de-~str'ing, but I had already converted it to use StrBuf, so we may as well leave it in. Update: no longer, this is removed in a later commit.
This commit is contained in:
commit
7932b719ec
@ -12,6 +12,7 @@
|
||||
// FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias`
|
||||
// and `nonnull`
|
||||
|
||||
use core::ptr::RawPtr;
|
||||
#[cfg(not(test))] use core::raw;
|
||||
#[cfg(not(test))] use util;
|
||||
|
||||
@ -69,6 +70,11 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
|
||||
/// the value returned by `usable_size` for the requested size.
|
||||
#[inline]
|
||||
pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) {
|
||||
// FIXME(14395) This is only required for DST ~[T], it should be removed once
|
||||
// we fix that representation to not use null pointers.
|
||||
if ptr.is_null() {
|
||||
return;
|
||||
}
|
||||
imp::deallocate(ptr, size, align)
|
||||
}
|
||||
|
||||
|
@ -2557,7 +2557,7 @@ mod tests {
|
||||
}
|
||||
|
||||
fn rng() -> rand::IsaacRng {
|
||||
let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
|
||||
let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
|
||||
rand::SeedableRng::from_seed(seed)
|
||||
}
|
||||
|
||||
|
@ -1088,7 +1088,8 @@ mod tests {
|
||||
let n = list_from([1i,2,3]);
|
||||
spawn(proc() {
|
||||
check_links(&n);
|
||||
assert_eq!(&[&1,&2,&3], n.iter().collect::<Vec<&int>>().as_slice());
|
||||
let a: &[_] = &[&1,&2,&3];
|
||||
assert_eq!(a, n.iter().collect::<Vec<&int>>().as_slice());
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -346,7 +346,8 @@ mod tests {
|
||||
assert_eq!(hasher.hash(&'a'), 97);
|
||||
|
||||
assert_eq!(hasher.hash(&("a")), 97 + 0xFF);
|
||||
assert_eq!(hasher.hash(& &[1u8, 2u8, 3u8]), 9);
|
||||
let cs: &[u8] = &[1u8, 2u8, 3u8];
|
||||
assert_eq!(hasher.hash(& cs), 9);
|
||||
|
||||
unsafe {
|
||||
let ptr: *const int = mem::transmute(5i);
|
||||
|
@ -495,8 +495,8 @@ mod tests {
|
||||
assert!(s != t && t != u);
|
||||
assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u));
|
||||
|
||||
let v = (&[1u8], &[0u8, 0], &[0u8]);
|
||||
let w = (&[1u8, 0, 0, 0], &[], &[]);
|
||||
let v: (&[u8], &[u8], &[u8]) = (&[1u8], &[0u8, 0], &[0u8]);
|
||||
let w: (&[u8], &[u8], &[u8]) = (&[1u8, 0, 0, 0], &[], &[]);
|
||||
|
||||
assert!(v != w);
|
||||
assert!(hash(&v) != hash(&w));
|
||||
|
@ -243,7 +243,8 @@ impl<T> RingBuf<T> {
|
||||
/// buf.push(5i);
|
||||
/// buf.push(3);
|
||||
/// buf.push(4);
|
||||
/// assert_eq!(buf.iter().collect::<Vec<&int>>().as_slice(), &[&5, &3, &4]);
|
||||
/// let b: &[_] = &[&5, &3, &4];
|
||||
/// assert_eq!(buf.iter().collect::<Vec<&int>>().as_slice(), b);
|
||||
/// ```
|
||||
pub fn iter<'a>(&'a self) -> Items<'a, T> {
|
||||
Items{index: 0, rindex: self.nelts, lo: self.lo, elts: self.elts.as_slice()}
|
||||
@ -263,7 +264,8 @@ impl<T> RingBuf<T> {
|
||||
/// for num in buf.mut_iter() {
|
||||
/// *num = *num - 2;
|
||||
/// }
|
||||
/// assert_eq!(buf.mut_iter().collect::<Vec<&mut int>>().as_slice(), &[&mut 3, &mut 1, &mut 2]);
|
||||
/// let b: &[_] = &[&mut 3, &mut 1, &mut 2];
|
||||
/// assert_eq!(buf.mut_iter().collect::<Vec<&mut int>>().as_slice(), b);
|
||||
/// ```
|
||||
pub fn mut_iter<'a>(&'a mut self) -> MutItems<'a, T> {
|
||||
let start_index = raw_index(self.lo, self.elts.len(), 0);
|
||||
@ -865,12 +867,18 @@ mod tests {
|
||||
for i in range(0i, 5) {
|
||||
d.push_back(i);
|
||||
}
|
||||
assert_eq!(d.iter().collect::<Vec<&int>>().as_slice(), &[&0,&1,&2,&3,&4]);
|
||||
{
|
||||
let b: &[_] = &[&0,&1,&2,&3,&4];
|
||||
assert_eq!(d.iter().collect::<Vec<&int>>().as_slice(), b);
|
||||
}
|
||||
|
||||
for i in range(6i, 9) {
|
||||
d.push_front(i);
|
||||
}
|
||||
assert_eq!(d.iter().collect::<Vec<&int>>().as_slice(), &[&8,&7,&6,&0,&1,&2,&3,&4]);
|
||||
{
|
||||
let b: &[_] = &[&8,&7,&6,&0,&1,&2,&3,&4];
|
||||
assert_eq!(d.iter().collect::<Vec<&int>>().as_slice(), b);
|
||||
}
|
||||
|
||||
let mut it = d.iter();
|
||||
let mut len = d.len();
|
||||
@ -890,12 +898,16 @@ mod tests {
|
||||
for i in range(0i, 5) {
|
||||
d.push_back(i);
|
||||
}
|
||||
assert_eq!(d.iter().rev().collect::<Vec<&int>>().as_slice(), &[&4,&3,&2,&1,&0]);
|
||||
{
|
||||
let b: &[_] = &[&4,&3,&2,&1,&0];
|
||||
assert_eq!(d.iter().rev().collect::<Vec<&int>>().as_slice(), b);
|
||||
}
|
||||
|
||||
for i in range(6i, 9) {
|
||||
d.push_front(i);
|
||||
}
|
||||
assert_eq!(d.iter().rev().collect::<Vec<&int>>().as_slice(), &[&4,&3,&2,&1,&0,&6,&7,&8]);
|
||||
let b: &[_] = &[&4,&3,&2,&1,&0,&6,&7,&8];
|
||||
assert_eq!(d.iter().rev().collect::<Vec<&int>>().as_slice(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -638,11 +638,13 @@ pub trait MutableOrdSlice<T> {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let v = &mut [0i, 1, 2];
|
||||
/// let v: &mut [_] = &mut [0i, 1, 2];
|
||||
/// v.next_permutation();
|
||||
/// assert_eq!(v, &mut [0i, 2, 1]);
|
||||
/// let b: &mut [_] = &mut [0i, 2, 1];
|
||||
/// assert!(v == b);
|
||||
/// v.next_permutation();
|
||||
/// assert_eq!(v, &mut [1i, 0, 2]);
|
||||
/// let b: &mut [_] = &mut [1i, 0, 2];
|
||||
/// assert!(v == b);
|
||||
/// ```
|
||||
fn next_permutation(self) -> bool;
|
||||
|
||||
@ -654,11 +656,13 @@ pub trait MutableOrdSlice<T> {
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// let v = &mut [1i, 0, 2];
|
||||
/// let v: &mut [_] = &mut [1i, 0, 2];
|
||||
/// v.prev_permutation();
|
||||
/// assert_eq!(v, &mut [0i, 2, 1]);
|
||||
/// let b: &mut [_] = &mut [0i, 2, 1];
|
||||
/// assert!(v == b);
|
||||
/// v.prev_permutation();
|
||||
/// assert_eq!(v, &mut [0i, 1, 2]);
|
||||
/// let b: &mut [_] = &mut [0i, 1, 2];
|
||||
/// assert!(v == b);
|
||||
/// ```
|
||||
fn prev_permutation(self) -> bool;
|
||||
}
|
||||
@ -845,9 +849,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_tail() {
|
||||
let mut a = vec![11i];
|
||||
assert_eq!(a.tail(), &[]);
|
||||
let b: &[int] = &[];
|
||||
assert_eq!(a.tail(), b);
|
||||
a = vec![11i, 12];
|
||||
assert_eq!(a.tail(), &[12]);
|
||||
let b: &[int] = &[12];
|
||||
assert_eq!(a.tail(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -860,9 +866,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_tailn() {
|
||||
let mut a = vec![11i, 12, 13];
|
||||
assert_eq!(a.tailn(0), &[11, 12, 13]);
|
||||
let b: &[int] = &[11, 12, 13];
|
||||
assert_eq!(a.tailn(0), b);
|
||||
a = vec![11i, 12, 13];
|
||||
assert_eq!(a.tailn(2), &[13]);
|
||||
let b: &[int] = &[13];
|
||||
assert_eq!(a.tailn(2), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -875,9 +883,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_init() {
|
||||
let mut a = vec![11i];
|
||||
assert_eq!(a.init(), &[]);
|
||||
let b: &[int] = &[];
|
||||
assert_eq!(a.init(), b);
|
||||
a = vec![11i, 12];
|
||||
assert_eq!(a.init(), &[11]);
|
||||
let b: &[int] = &[11];
|
||||
assert_eq!(a.init(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -890,9 +900,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_initn() {
|
||||
let mut a = vec![11i, 12, 13];
|
||||
assert_eq!(a.as_slice().initn(0), &[11, 12, 13]);
|
||||
let b: &[int] = &[11, 12, 13];
|
||||
assert_eq!(a.as_slice().initn(0), b);
|
||||
a = vec![11i, 12, 13];
|
||||
assert_eq!(a.as_slice().initn(2), &[11]);
|
||||
let b: &[int] = &[11];
|
||||
assert_eq!(a.as_slice().initn(2), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -945,18 +957,22 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_slice_from() {
|
||||
let vec = &[1i, 2, 3, 4];
|
||||
let vec: &[int] = &[1, 2, 3, 4];
|
||||
assert_eq!(vec.slice_from(0), vec);
|
||||
assert_eq!(vec.slice_from(2), &[3, 4]);
|
||||
assert_eq!(vec.slice_from(4), &[]);
|
||||
let b: &[int] = &[3, 4];
|
||||
assert_eq!(vec.slice_from(2), b);
|
||||
let b: &[int] = &[];
|
||||
assert_eq!(vec.slice_from(4), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_slice_to() {
|
||||
let vec = &[1i, 2, 3, 4];
|
||||
let vec: &[int] = &[1, 2, 3, 4];
|
||||
assert_eq!(vec.slice_to(4), vec);
|
||||
assert_eq!(vec.slice_to(2), &[1, 2]);
|
||||
assert_eq!(vec.slice_to(0), &[]);
|
||||
let b: &[int] = &[1, 2];
|
||||
assert_eq!(vec.slice_to(2), b);
|
||||
let b: &[int] = &[];
|
||||
assert_eq!(vec.slice_to(0), b);
|
||||
}
|
||||
|
||||
|
||||
@ -1210,23 +1226,30 @@ mod tests {
|
||||
let v : &mut[int] = &mut[1i, 2, 3, 4, 5];
|
||||
assert!(v.prev_permutation() == false);
|
||||
assert!(v.next_permutation());
|
||||
assert_eq!(v, &mut[1, 2, 3, 5, 4]);
|
||||
let b: &mut[int] = &mut[1, 2, 3, 5, 4];
|
||||
assert!(v == b);
|
||||
assert!(v.prev_permutation());
|
||||
assert_eq!(v, &mut[1, 2, 3, 4, 5]);
|
||||
let b: &mut[int] = &mut[1, 2, 3, 4, 5];
|
||||
assert!(v == b);
|
||||
assert!(v.next_permutation());
|
||||
assert!(v.next_permutation());
|
||||
assert_eq!(v, &mut[1, 2, 4, 3, 5]);
|
||||
let b: &mut[int] = &mut[1, 2, 4, 3, 5];
|
||||
assert!(v == b);
|
||||
assert!(v.next_permutation());
|
||||
assert_eq!(v, &mut[1, 2, 4, 5, 3]);
|
||||
let b: &mut[int] = &mut[1, 2, 4, 5, 3];
|
||||
assert!(v == b);
|
||||
|
||||
let v : &mut[int] = &mut[1i, 0, 0, 0];
|
||||
assert!(v.next_permutation() == false);
|
||||
assert!(v.prev_permutation());
|
||||
assert_eq!(v, &mut[0, 1, 0, 0]);
|
||||
let b: &mut[int] = &mut[0, 1, 0, 0];
|
||||
assert!(v == b);
|
||||
assert!(v.prev_permutation());
|
||||
assert_eq!(v, &mut[0, 0, 1, 0]);
|
||||
let b: &mut[int] = &mut[0, 0, 1, 0];
|
||||
assert!(v == b);
|
||||
assert!(v.prev_permutation());
|
||||
assert_eq!(v, &mut[0, 0, 0, 1]);
|
||||
let b: &mut[int] = &mut[0, 0, 0, 1];
|
||||
assert!(v == b);
|
||||
assert!(v.prev_permutation() == false);
|
||||
}
|
||||
|
||||
@ -1234,27 +1257,31 @@ mod tests {
|
||||
fn test_lexicographic_permutations_empty_and_short() {
|
||||
let empty : &mut[int] = &mut[];
|
||||
assert!(empty.next_permutation() == false);
|
||||
assert_eq!(empty, &mut[]);
|
||||
let b: &mut[int] = &mut[];
|
||||
assert!(empty == b);
|
||||
assert!(empty.prev_permutation() == false);
|
||||
assert_eq!(empty, &mut[]);
|
||||
assert!(empty == b);
|
||||
|
||||
let one_elem : &mut[int] = &mut[4i];
|
||||
assert!(one_elem.prev_permutation() == false);
|
||||
assert_eq!(one_elem, &mut[4]);
|
||||
let b: &mut[int] = &mut[4];
|
||||
assert!(one_elem == b);
|
||||
assert!(one_elem.next_permutation() == false);
|
||||
assert_eq!(one_elem, &mut[4]);
|
||||
assert!(one_elem == b);
|
||||
|
||||
let two_elem : &mut[int] = &mut[1i, 2];
|
||||
assert!(two_elem.prev_permutation() == false);
|
||||
assert_eq!(two_elem, &mut[1, 2]);
|
||||
let b : &mut[int] = &mut[1, 2];
|
||||
let c : &mut[int] = &mut[2, 1];
|
||||
assert!(two_elem == b);
|
||||
assert!(two_elem.next_permutation());
|
||||
assert_eq!(two_elem, &mut[2, 1]);
|
||||
assert!(two_elem == c);
|
||||
assert!(two_elem.next_permutation() == false);
|
||||
assert_eq!(two_elem, &mut[2, 1]);
|
||||
assert!(two_elem == c);
|
||||
assert!(two_elem.prev_permutation());
|
||||
assert_eq!(two_elem, &mut[1, 2]);
|
||||
assert!(two_elem == b);
|
||||
assert!(two_elem.prev_permutation() == false);
|
||||
assert_eq!(two_elem, &mut[1, 2]);
|
||||
assert!(two_elem == b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1408,7 +1435,10 @@ mod tests {
|
||||
assert_eq!(v.concat_vec(), vec![]);
|
||||
assert_eq!([vec![1i], vec![2i,3i]].concat_vec(), vec![1, 2, 3]);
|
||||
|
||||
assert_eq!([&[1i], &[2i,3i]].concat_vec(), vec![1, 2, 3]);
|
||||
let v: [&[int], ..2] = [&[1], &[2, 3]];
|
||||
assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 3]);
|
||||
let v: [&[int], ..3] = [&[1], &[2], &[3]];
|
||||
assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 0, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1418,8 +1448,10 @@ mod tests {
|
||||
assert_eq!([vec![1i], vec![2i, 3]].connect_vec(&0), vec![1, 0, 2, 3]);
|
||||
assert_eq!([vec![1i], vec![2i], vec![3i]].connect_vec(&0), vec![1, 0, 2, 0, 3]);
|
||||
|
||||
assert_eq!([&[1i], &[2i, 3]].connect_vec(&0), vec![1, 0, 2, 3]);
|
||||
assert_eq!([&[1i], &[2i], &[3]].connect_vec(&0), vec![1, 0, 2, 0, 3]);
|
||||
let v: [&[int], ..2] = [&[1], &[2, 3]];
|
||||
assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 3]);
|
||||
let v: [&[int], ..3] = [&[1], &[2], &[3]];
|
||||
assert_eq!(v.connect_vec(&0), vec![1, 0, 2, 0, 3]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1577,11 +1609,16 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_total_ord() {
|
||||
[1i, 2, 3, 4].cmp(& &[1, 2, 3]) == Greater;
|
||||
[1i, 2, 3].cmp(& &[1, 2, 3, 4]) == Less;
|
||||
[1i, 2, 3, 4].cmp(& &[1, 2, 3, 4]) == Equal;
|
||||
[1i, 2, 3, 4, 5, 5, 5, 5].cmp(& &[1, 2, 3, 4, 5, 6]) == Less;
|
||||
[2i, 2].cmp(& &[1, 2, 3, 4]) == Greater;
|
||||
let c: &[int] = &[1, 2, 3];
|
||||
[1, 2, 3, 4].cmp(& c) == Greater;
|
||||
let c: &[int] = &[1, 2, 3, 4];
|
||||
[1, 2, 3].cmp(& c) == Less;
|
||||
let c: &[int] = &[1, 2, 3, 6];
|
||||
[1, 2, 3, 4].cmp(& c) == Equal;
|
||||
let c: &[int] = &[1, 2, 3, 4, 5, 6];
|
||||
[1, 2, 3, 4, 5, 5, 5, 5].cmp(& c) == Less;
|
||||
let c: &[int] = &[1, 2, 3, 4];
|
||||
[2, 2].cmp(& c) == Greater;
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1705,74 +1742,95 @@ mod tests {
|
||||
fn test_splitator() {
|
||||
let xs = &[1i,2,3,4,5];
|
||||
|
||||
let splits: &[&[int]] = &[&[1], &[3], &[5]];
|
||||
assert_eq!(xs.split(|x| *x % 2 == 0).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[1], &[3], &[5]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[], &[2,3,4,5]];
|
||||
assert_eq!(xs.split(|x| *x == 1).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[], &[2,3,4,5]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[1,2,3,4], &[]];
|
||||
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[1,2,3,4], &[]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[1,2,3,4,5]];
|
||||
assert_eq!(xs.split(|x| *x == 10).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[1,2,3,4,5]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[], &[], &[], &[], &[], &[]];
|
||||
assert_eq!(xs.split(|_| true).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[], &[], &[], &[], &[], &[]]);
|
||||
splits);
|
||||
|
||||
let xs: &[int] = &[];
|
||||
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<&[int]>>().as_slice(), &[&[]]);
|
||||
let splits: &[&[int]] = &[&[]];
|
||||
assert_eq!(xs.split(|x| *x == 5).collect::<Vec<&[int]>>().as_slice(), splits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_splitnator() {
|
||||
let xs = &[1i,2,3,4,5];
|
||||
|
||||
let splits: &[&[int]] = &[&[1,2,3,4,5]];
|
||||
assert_eq!(xs.splitn(0, |x| *x % 2 == 0).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[1,2,3,4,5]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[1], &[3,4,5]];
|
||||
assert_eq!(xs.splitn(1, |x| *x % 2 == 0).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[1], &[3,4,5]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[], &[], &[], &[4,5]];
|
||||
assert_eq!(xs.splitn(3, |_| true).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[], &[], &[], &[4,5]]);
|
||||
splits);
|
||||
|
||||
let xs: &[int] = &[];
|
||||
assert_eq!(xs.splitn(1, |x| *x == 5).collect::<Vec<&[int]>>().as_slice(), &[&[]]);
|
||||
let splits: &[&[int]] = &[&[]];
|
||||
assert_eq!(xs.splitn(1, |x| *x == 5).collect::<Vec<&[int]>>().as_slice(), splits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rsplitator() {
|
||||
let xs = &[1i,2,3,4,5];
|
||||
|
||||
let splits: &[&[int]] = &[&[5], &[3], &[1]];
|
||||
assert_eq!(xs.split(|x| *x % 2 == 0).rev().collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[5], &[3], &[1]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[2,3,4,5], &[]];
|
||||
assert_eq!(xs.split(|x| *x == 1).rev().collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[2,3,4,5], &[]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[], &[1,2,3,4]];
|
||||
assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[], &[1,2,3,4]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[1,2,3,4,5]];
|
||||
assert_eq!(xs.split(|x| *x == 10).rev().collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[1,2,3,4,5]]);
|
||||
splits);
|
||||
|
||||
let xs: &[int] = &[];
|
||||
assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<&[int]>>().as_slice(), &[&[]]);
|
||||
let splits: &[&[int]] = &[&[]];
|
||||
assert_eq!(xs.split(|x| *x == 5).rev().collect::<Vec<&[int]>>().as_slice(), splits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_rsplitnator() {
|
||||
let xs = &[1,2,3,4,5];
|
||||
|
||||
let splits: &[&[int]] = &[&[1,2,3,4,5]];
|
||||
assert_eq!(xs.rsplitn(0, |x| *x % 2 == 0).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[1,2,3,4,5]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[5], &[1,2,3]];
|
||||
assert_eq!(xs.rsplitn(1, |x| *x % 2 == 0).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[5], &[1,2,3]]);
|
||||
splits);
|
||||
let splits: &[&[int]] = &[&[], &[], &[], &[1,2]];
|
||||
assert_eq!(xs.rsplitn(3, |_| true).collect::<Vec<&[int]>>().as_slice(),
|
||||
&[&[], &[], &[], &[1,2]]);
|
||||
splits);
|
||||
|
||||
let xs: &[int] = &[];
|
||||
assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::<Vec<&[int]>>().as_slice(), &[&[]]);
|
||||
let splits: &[&[int]] = &[&[]];
|
||||
assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::<Vec<&[int]>>().as_slice(), splits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_windowsator() {
|
||||
let v = &[1i,2,3,4];
|
||||
|
||||
assert_eq!(v.windows(2).collect::<Vec<&[int]>>().as_slice(), &[&[1,2], &[2,3], &[3,4]]);
|
||||
assert_eq!(v.windows(3).collect::<Vec<&[int]>>().as_slice(), &[&[1i,2,3], &[2,3,4]]);
|
||||
let wins: &[&[int]] = &[&[1,2], &[2,3], &[3,4]];
|
||||
assert_eq!(v.windows(2).collect::<Vec<&[int]>>().as_slice(), wins);
|
||||
let wins: &[&[int]] = &[&[1i,2,3], &[2,3,4]];
|
||||
assert_eq!(v.windows(3).collect::<Vec<&[int]>>().as_slice(), wins);
|
||||
assert!(v.windows(6).next().is_none());
|
||||
}
|
||||
|
||||
@ -1787,16 +1845,23 @@ mod tests {
|
||||
fn test_chunksator() {
|
||||
let v = &[1i,2,3,4,5];
|
||||
|
||||
assert_eq!(v.chunks(2).collect::<Vec<&[int]>>().as_slice(), &[&[1i,2], &[3,4], &[5]]);
|
||||
assert_eq!(v.chunks(3).collect::<Vec<&[int]>>().as_slice(), &[&[1i,2,3], &[4,5]]);
|
||||
assert_eq!(v.chunks(6).collect::<Vec<&[int]>>().as_slice(), &[&[1i,2,3,4,5]]);
|
||||
let chunks: &[&[int]] = &[&[1i,2], &[3,4], &[5]];
|
||||
assert_eq!(v.chunks(2).collect::<Vec<&[int]>>().as_slice(), chunks);
|
||||
let chunks: &[&[int]] = &[&[1i,2,3], &[4,5]];
|
||||
assert_eq!(v.chunks(3).collect::<Vec<&[int]>>().as_slice(), chunks);
|
||||
let chunks: &[&[int]] = &[&[1i,2,3,4,5]];
|
||||
assert_eq!(v.chunks(6).collect::<Vec<&[int]>>().as_slice(), chunks);
|
||||
|
||||
assert_eq!(v.chunks(2).rev().collect::<Vec<&[int]>>().as_slice(), &[&[5i], &[3,4], &[1,2]]);
|
||||
let chunks: &[&[int]] = &[&[5i], &[3,4], &[1,2]];
|
||||
assert_eq!(v.chunks(2).rev().collect::<Vec<&[int]>>().as_slice(), chunks);
|
||||
let mut it = v.chunks(2);
|
||||
assert_eq!(it.indexable(), 3);
|
||||
assert_eq!(it.idx(0).unwrap(), &[1,2]);
|
||||
assert_eq!(it.idx(1).unwrap(), &[3,4]);
|
||||
assert_eq!(it.idx(2).unwrap(), &[5]);
|
||||
let chunk: &[int] = &[1,2];
|
||||
assert_eq!(it.idx(0).unwrap(), chunk);
|
||||
let chunk: &[int] = &[3,4];
|
||||
assert_eq!(it.idx(1).unwrap(), chunk);
|
||||
let chunk: &[int] = &[5];
|
||||
assert_eq!(it.idx(2).unwrap(), chunk);
|
||||
assert_eq!(it.idx(3), None);
|
||||
}
|
||||
|
||||
@ -1864,10 +1929,12 @@ mod tests {
|
||||
|
||||
let empty_mut: &mut [int] = &mut[];
|
||||
test_show_vec!(empty_mut, "[]".to_string());
|
||||
test_show_vec!(&mut[1i], "[1]".to_string());
|
||||
test_show_vec!(&mut[1i, 2, 3], "[1, 2, 3]".to_string());
|
||||
test_show_vec!(&mut[&mut[], &mut[1u], &mut[1u, 1u]],
|
||||
"[[], [1], [1, 1]]".to_string());
|
||||
let v: &mut[int] = &mut[1];
|
||||
test_show_vec!(v, "[1]".to_string());
|
||||
let v: &mut[int] = &mut[1, 2, 3];
|
||||
test_show_vec!(v, "[1, 2, 3]".to_string());
|
||||
let v: &mut [&mut[uint]] = &mut[&mut[], &mut[1u], &mut[1u, 1u]];
|
||||
test_show_vec!(v, "[[], [1], [1, 1]]".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1265,12 +1265,14 @@ mod tests {
|
||||
fn test_trim_left_chars() {
|
||||
let v: &[char] = &[];
|
||||
assert_eq!(" *** foo *** ".trim_left_chars(v), " *** foo *** ");
|
||||
assert_eq!(" *** foo *** ".trim_left_chars(&['*', ' ']), "foo *** ");
|
||||
assert_eq!(" *** *** ".trim_left_chars(&['*', ' ']), "");
|
||||
assert_eq!("foo *** ".trim_left_chars(&['*', ' ']), "foo *** ");
|
||||
let chars: &[char] = &['*', ' '];
|
||||
assert_eq!(" *** foo *** ".trim_left_chars(chars), "foo *** ");
|
||||
assert_eq!(" *** *** ".trim_left_chars(chars), "");
|
||||
assert_eq!("foo *** ".trim_left_chars(chars), "foo *** ");
|
||||
|
||||
assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11");
|
||||
assert_eq!("12foo1bar12".trim_left_chars(&['1', '2']), "foo1bar12");
|
||||
let chars: &[char] = &['1', '2'];
|
||||
assert_eq!("12foo1bar12".trim_left_chars(chars), "foo1bar12");
|
||||
assert_eq!("123foo1bar123".trim_left_chars(|c: char| c.is_digit()), "foo1bar123");
|
||||
}
|
||||
|
||||
@ -1278,12 +1280,14 @@ mod tests {
|
||||
fn test_trim_right_chars() {
|
||||
let v: &[char] = &[];
|
||||
assert_eq!(" *** foo *** ".trim_right_chars(v), " *** foo *** ");
|
||||
assert_eq!(" *** foo *** ".trim_right_chars(&['*', ' ']), " *** foo");
|
||||
assert_eq!(" *** *** ".trim_right_chars(&['*', ' ']), "");
|
||||
assert_eq!(" *** foo".trim_right_chars(&['*', ' ']), " *** foo");
|
||||
let chars: &[char] = &['*', ' '];
|
||||
assert_eq!(" *** foo *** ".trim_right_chars(chars), " *** foo");
|
||||
assert_eq!(" *** *** ".trim_right_chars(chars), "");
|
||||
assert_eq!(" *** foo".trim_right_chars(chars), " *** foo");
|
||||
|
||||
assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar");
|
||||
assert_eq!("12foo1bar12".trim_right_chars(&['1', '2']), "12foo1bar");
|
||||
let chars: &[char] = &['1', '2'];
|
||||
assert_eq!("12foo1bar12".trim_right_chars(chars), "12foo1bar");
|
||||
assert_eq!("123foo1bar123".trim_right_chars(|c: char| c.is_digit()), "123foo1bar");
|
||||
}
|
||||
|
||||
@ -1291,12 +1295,14 @@ mod tests {
|
||||
fn test_trim_chars() {
|
||||
let v: &[char] = &[];
|
||||
assert_eq!(" *** foo *** ".trim_chars(v), " *** foo *** ");
|
||||
assert_eq!(" *** foo *** ".trim_chars(&['*', ' ']), "foo");
|
||||
assert_eq!(" *** *** ".trim_chars(&['*', ' ']), "");
|
||||
assert_eq!("foo".trim_chars(&['*', ' ']), "foo");
|
||||
let chars: &[char] = &['*', ' '];
|
||||
assert_eq!(" *** foo *** ".trim_chars(chars), "foo");
|
||||
assert_eq!(" *** *** ".trim_chars(chars), "");
|
||||
assert_eq!("foo".trim_chars(chars), "foo");
|
||||
|
||||
assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar");
|
||||
assert_eq!("12foo1bar12".trim_chars(&['1', '2']), "foo1bar");
|
||||
let chars: &[char] = &['1', '2'];
|
||||
assert_eq!("12foo1bar12".trim_chars(chars), "foo1bar");
|
||||
assert_eq!("123foo1bar123".trim_chars(|c: char| c.is_digit()), "foo1bar");
|
||||
}
|
||||
|
||||
@ -1443,7 +1449,8 @@ mod tests {
|
||||
184, 173, 229, 141, 142, 86, 105, 225, 187, 135, 116, 32, 78, 97,
|
||||
109
|
||||
];
|
||||
assert_eq!("".as_bytes(), &[]);
|
||||
let b: &[u8] = &[];
|
||||
assert_eq!("".as_bytes(), b);
|
||||
assert_eq!("abc".as_bytes(), b"abc");
|
||||
assert_eq!("ศไทย中华Việt Nam".as_bytes(), v.as_slice());
|
||||
}
|
||||
@ -1542,19 +1549,23 @@ mod tests {
|
||||
#[test]
|
||||
fn test_truncate_utf16_at_nul() {
|
||||
let v = [];
|
||||
assert_eq!(truncate_utf16_at_nul(v), &[]);
|
||||
let b: &[u16] = &[];
|
||||
assert_eq!(truncate_utf16_at_nul(v), b);
|
||||
|
||||
let v = [0, 2, 3];
|
||||
assert_eq!(truncate_utf16_at_nul(v), &[]);
|
||||
assert_eq!(truncate_utf16_at_nul(v), b);
|
||||
|
||||
let v = [1, 0, 3];
|
||||
assert_eq!(truncate_utf16_at_nul(v), &[1]);
|
||||
let b: &[u16] = &[1];
|
||||
assert_eq!(truncate_utf16_at_nul(v), b);
|
||||
|
||||
let v = [1, 2, 0];
|
||||
assert_eq!(truncate_utf16_at_nul(v), &[1, 2]);
|
||||
let b: &[u16] = &[1, 2];
|
||||
assert_eq!(truncate_utf16_at_nul(v), b);
|
||||
|
||||
let v = [1, 2, 3];
|
||||
assert_eq!(truncate_utf16_at_nul(v), &[1, 2, 3]);
|
||||
let b: &[u16] = &[1, 2, 3];
|
||||
assert_eq!(truncate_utf16_at_nul(v), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1960,7 +1971,7 @@ mod tests {
|
||||
use std::iter::order;
|
||||
// official Unicode test data
|
||||
// from http://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakTest.txt
|
||||
let test_same = [
|
||||
let test_same: [(_, &[_]), .. 325] = [
|
||||
("\u0020\u0020", &["\u0020", "\u0020"]), ("\u0020\u0308\u0020", &["\u0020\u0308",
|
||||
"\u0020"]), ("\u0020\u000D", &["\u0020", "\u000D"]), ("\u0020\u0308\u000D",
|
||||
&["\u0020\u0308", "\u000D"]), ("\u0020\u000A", &["\u0020", "\u000A"]),
|
||||
@ -2169,7 +2180,7 @@ mod tests {
|
||||
("\u0646\u200D\u0020", &["\u0646\u200D", "\u0020"]),
|
||||
];
|
||||
|
||||
let test_diff = [
|
||||
let test_diff: [(_, &[_], &[_]), .. 23] = [
|
||||
("\u0020\u0903", &["\u0020\u0903"], &["\u0020", "\u0903"]), ("\u0020\u0308\u0903",
|
||||
&["\u0020\u0308\u0903"], &["\u0020\u0308", "\u0903"]), ("\u000D\u0308\u0903",
|
||||
&["\u000D", "\u0308\u0903"], &["\u000D", "\u0308", "\u0903"]), ("\u000A\u0308\u0903",
|
||||
@ -2218,9 +2229,11 @@ mod tests {
|
||||
// test the indices iterators
|
||||
let s = "a̐éö̲\r\n";
|
||||
let gr_inds = s.grapheme_indices(true).collect::<Vec<(uint, &str)>>();
|
||||
assert_eq!(gr_inds.as_slice(), &[(0u, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]);
|
||||
let b: &[_] = &[(0u, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")];
|
||||
assert_eq!(gr_inds.as_slice(), b);
|
||||
let gr_inds = s.grapheme_indices(true).rev().collect::<Vec<(uint, &str)>>();
|
||||
assert_eq!(gr_inds.as_slice(), &[(11, "\r\n"), (6, "ö̲"), (3, "é"), (0u, "a̐")]);
|
||||
let b: &[_] = &[(11, "\r\n"), (6, "ö̲"), (3, "é"), (0u, "a̐")];
|
||||
assert_eq!(gr_inds.as_slice(), b);
|
||||
let mut gr_inds = s.grapheme_indices(true);
|
||||
let e1 = gr_inds.size_hint();
|
||||
assert_eq!(e1, (1, Some(13)));
|
||||
@ -2232,7 +2245,8 @@ mod tests {
|
||||
// make sure the reverse iterator does the right thing with "\n" at beginning of string
|
||||
let s = "\n\r\n\r";
|
||||
let gr = s.graphemes(true).rev().collect::<Vec<&str>>();
|
||||
assert_eq!(gr.as_slice(), &["\r", "\r\n", "\n"]);
|
||||
let b: &[_] = &["\r", "\r\n", "\n"];
|
||||
assert_eq!(gr.as_slice(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -2494,7 +2508,8 @@ mod bench {
|
||||
let s = "Mary had a little lamb, Little lamb, little-lamb.";
|
||||
let len = s.split(' ').count();
|
||||
|
||||
b.iter(|| assert_eq!(s.split(&[' ']).count(), len));
|
||||
let c: &[char] = &[' '];
|
||||
b.iter(|| assert_eq!(s.split(c).count(), len));
|
||||
}
|
||||
|
||||
#[bench]
|
||||
|
@ -531,7 +531,8 @@ impl String {
|
||||
///
|
||||
/// ```
|
||||
/// let s = String::from_str("hello");
|
||||
/// assert_eq!(s.as_bytes(), &[104, 101, 108, 108, 111]);
|
||||
/// let b: &[_] = &[104, 101, 108, 108, 111];
|
||||
/// assert_eq!(s.as_bytes(), b);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn as_bytes<'a>(&'a self) -> &'a [u8] {
|
||||
@ -552,7 +553,8 @@ impl String {
|
||||
/// bytes[1] = 51;
|
||||
/// bytes[4] = 48;
|
||||
/// }
|
||||
/// assert_eq!(s.as_bytes(), &[104, 51, 108, 108, 48]);
|
||||
/// let b: &[_] = &[104, 51, 108, 108, 48];
|
||||
/// assert_eq!(s.as_bytes(), b);
|
||||
/// assert_eq!(s.as_slice(), "h3ll0")
|
||||
/// ```
|
||||
#[inline]
|
||||
|
@ -1853,7 +1853,8 @@ mod test_treemap {
|
||||
check_equal(ctrl.as_slice(), &map);
|
||||
assert!(map.find(&5).is_none());
|
||||
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(&[42]);
|
||||
let seed: &[_] = &[42];
|
||||
let mut rng: rand::IsaacRng = rand::SeedableRng::from_seed(seed);
|
||||
|
||||
for _ in range(0u, 3) {
|
||||
for _ in range(0u, 90) {
|
||||
|
@ -112,12 +112,13 @@ impl Ordering {
|
||||
/// assert_eq!(Greater.reverse(), Less);
|
||||
///
|
||||
///
|
||||
/// let mut data = &mut [2u, 10, 5, 8];
|
||||
/// let mut data: &mut [_] = &mut [2u, 10, 5, 8];
|
||||
///
|
||||
/// // sort the array from largest to smallest.
|
||||
/// data.sort_by(|a, b| a.cmp(b).reverse());
|
||||
///
|
||||
/// assert_eq!(data, &mut [10u, 8, 5, 2]);
|
||||
/// let b: &mut [_] = &mut [10u, 8, 5, 2];
|
||||
/// assert!(data == b);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[experimental]
|
||||
|
@ -93,6 +93,8 @@ pub trait TyVisitor {
|
||||
fn visit_char(&mut self) -> bool;
|
||||
|
||||
fn visit_estr_slice(&mut self) -> bool;
|
||||
// NOTE: remove after snapshot
|
||||
#[cfg(stage0)]
|
||||
fn visit_estr_fixed(&mut self, n: uint, sz: uint, align: uint) -> bool;
|
||||
|
||||
fn visit_box(&mut self, mtbl: uint, inner: *const TyDesc) -> bool;
|
||||
@ -101,8 +103,13 @@ pub trait TyVisitor {
|
||||
fn visit_rptr(&mut self, mtbl: uint, inner: *const TyDesc) -> bool;
|
||||
|
||||
fn visit_evec_slice(&mut self, mtbl: uint, inner: *const TyDesc) -> bool;
|
||||
// NOTE: remove after snapshot
|
||||
#[cfg(stage0)]
|
||||
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
|
||||
mtbl: uint, inner: *const TyDesc) -> bool;
|
||||
#[cfg(not(stage0))]
|
||||
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
|
||||
inner: *const TyDesc) -> bool;
|
||||
|
||||
fn visit_enter_rec(&mut self, n_fields: uint,
|
||||
sz: uint, align: uint) -> bool;
|
||||
|
@ -174,7 +174,7 @@ pub unsafe fn overwrite<T>(dst: *mut T, src: T) {
|
||||
|
||||
/// Deprecated, use `overwrite` instead
|
||||
#[inline]
|
||||
#[deprecated = "use ptr::write"]
|
||||
#[deprecated = "this function has been renamed to overwrite()"]
|
||||
pub unsafe fn move_val_init<T>(dst: &mut T, src: T) {
|
||||
ptr::write(dst, src)
|
||||
}
|
||||
|
@ -221,8 +221,14 @@ impl<T> Option<T> {
|
||||
#[inline]
|
||||
pub fn as_mut_slice<'r>(&'r mut self) -> &'r mut [T] {
|
||||
match *self {
|
||||
Some(ref mut x) => slice::mut_ref_slice(x),
|
||||
None => &mut []
|
||||
Some(ref mut x) => {
|
||||
let result: &mut [T] = slice::mut_ref_slice(x);
|
||||
result
|
||||
}
|
||||
None => {
|
||||
let result: &mut [T] = &mut [];
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,7 +530,10 @@ impl<T> Slice<T> for Option<T> {
|
||||
fn as_slice<'a>(&'a self) -> &'a [T] {
|
||||
match *self {
|
||||
Some(ref x) => slice::ref_slice(x),
|
||||
None => &[]
|
||||
None => {
|
||||
let result: &[_] = &[];
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,10 +51,16 @@ pub struct Procedure {
|
||||
///
|
||||
/// This struct does not have a `Repr` implementation
|
||||
/// because there is no way to refer to all trait objects generically.
|
||||
#[cfg(stage0)]
|
||||
pub struct TraitObject {
|
||||
pub vtable: *mut (),
|
||||
pub data: *mut (),
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
pub struct TraitObject {
|
||||
pub data: *mut (),
|
||||
pub vtable: *mut (),
|
||||
}
|
||||
|
||||
/// This trait is meant to map equivalences between raw structs and their
|
||||
/// corresponding rust values.
|
||||
|
@ -1623,7 +1623,6 @@ pub mod bytes {
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Boilerplate traits
|
||||
//
|
||||
@ -1649,6 +1648,27 @@ impl<'a,T:PartialEq, V: Slice<T>> Equiv<V> for &'a [T] {
|
||||
fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
|
||||
}
|
||||
|
||||
#[unstable = "waiting for DST"]
|
||||
impl<'a,T:PartialEq> PartialEq for &'a mut [T] {
|
||||
fn eq(&self, other: & &'a mut [T]) -> bool {
|
||||
self.len() == other.len() &&
|
||||
order::eq(self.iter(), other.iter())
|
||||
}
|
||||
fn ne(&self, other: & &'a mut [T]) -> bool {
|
||||
self.len() != other.len() ||
|
||||
order::ne(self.iter(), other.iter())
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable = "waiting for DST"]
|
||||
impl<'a,T:Eq> Eq for &'a mut [T] {}
|
||||
|
||||
#[unstable = "waiting for DST"]
|
||||
impl<'a,T:PartialEq, V: Slice<T>> Equiv<V> for &'a mut [T] {
|
||||
#[inline]
|
||||
fn equiv(&self, other: &V) -> bool { self.as_slice() == other.as_slice() }
|
||||
}
|
||||
|
||||
#[unstable = "waiting for DST"]
|
||||
impl<'a,T:Ord> Ord for &'a [T] {
|
||||
fn cmp(&self, other: & &'a [T]) -> Ordering {
|
||||
|
@ -918,8 +918,8 @@ pub fn utf16_items<'a>(v: &'a [u16]) -> Utf16Items<'a> {
|
||||
///
|
||||
/// // "ab\0d"
|
||||
/// v[2] = 0;
|
||||
/// assert_eq!(str::truncate_utf16_at_nul(v),
|
||||
/// &['a' as u16, 'b' as u16]);
|
||||
/// let b: &[_] = &['a' as u16, 'b' as u16];
|
||||
/// assert_eq!(str::truncate_utf16_at_nul(v), b);
|
||||
/// ```
|
||||
pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
|
||||
match v.iter().position(|c| *c == 0) {
|
||||
@ -1439,7 +1439,8 @@ pub trait StrSlice<'a> {
|
||||
///
|
||||
/// ```rust
|
||||
/// assert_eq!("11foo1bar11".trim_chars('1'), "foo1bar")
|
||||
/// assert_eq!("12foo1bar12".trim_chars(&['1', '2']), "foo1bar")
|
||||
/// let x: &[_] = &['1', '2'];
|
||||
/// assert_eq!("12foo1bar12".trim_chars(x), "foo1bar")
|
||||
/// assert_eq!("123foo1bar123".trim_chars(|c: char| c.is_digit()), "foo1bar")
|
||||
/// ```
|
||||
fn trim_chars<C: CharEq>(&self, to_trim: C) -> &'a str;
|
||||
@ -1454,7 +1455,8 @@ pub trait StrSlice<'a> {
|
||||
///
|
||||
/// ```rust
|
||||
/// assert_eq!("11foo1bar11".trim_left_chars('1'), "foo1bar11")
|
||||
/// assert_eq!("12foo1bar12".trim_left_chars(&['1', '2']), "foo1bar12")
|
||||
/// let x: &[_] = &['1', '2'];
|
||||
/// assert_eq!("12foo1bar12".trim_left_chars(x), "foo1bar12")
|
||||
/// assert_eq!("123foo1bar123".trim_left_chars(|c: char| c.is_digit()), "foo1bar123")
|
||||
/// ```
|
||||
fn trim_left_chars<C: CharEq>(&self, to_trim: C) -> &'a str;
|
||||
@ -1469,7 +1471,8 @@ pub trait StrSlice<'a> {
|
||||
///
|
||||
/// ```rust
|
||||
/// assert_eq!("11foo1bar11".trim_right_chars('1'), "11foo1bar")
|
||||
/// assert_eq!("12foo1bar12".trim_right_chars(&['1', '2']), "12foo1bar")
|
||||
/// let x: &[_] = &['1', '2'];
|
||||
/// assert_eq!("12foo1bar12".trim_right_chars(x), "12foo1bar")
|
||||
/// assert_eq!("123foo1bar123".trim_right_chars(|c: char| c.is_digit()), "123foo1bar")
|
||||
/// ```
|
||||
fn trim_right_chars<C: CharEq>(&self, to_trim: C) -> &'a str;
|
||||
@ -1620,7 +1623,8 @@ pub trait StrSlice<'a> {
|
||||
/// assert_eq!(s.find(|c: char| c.is_whitespace()), Some(5));
|
||||
///
|
||||
/// // neither are found
|
||||
/// assert_eq!(s.find(&['1', '2']), None);
|
||||
/// let x: &[_] = &['1', '2'];
|
||||
/// assert_eq!(s.find(x), None);
|
||||
/// ```
|
||||
fn find<C: CharEq>(&self, search: C) -> Option<uint>;
|
||||
|
||||
@ -1644,7 +1648,8 @@ pub trait StrSlice<'a> {
|
||||
/// assert_eq!(s.rfind(|c: char| c.is_whitespace()), Some(12));
|
||||
///
|
||||
/// // searches for an occurrence of either `1` or `2`, but neither are found
|
||||
/// assert_eq!(s.rfind(&['1', '2']), None);
|
||||
/// let x: &[_] = &['1', '2'];
|
||||
/// assert_eq!(s.rfind(x), None);
|
||||
/// ```
|
||||
fn rfind<C: CharEq>(&self, search: C) -> Option<uint>;
|
||||
|
||||
|
@ -368,7 +368,7 @@ fn test_collect() {
|
||||
|
||||
#[test]
|
||||
fn test_all() {
|
||||
let v: Box<&[int]> = box &[1i, 2, 3, 4, 5];
|
||||
let v: Box<[int]> = box [1i, 2, 3, 4, 5];
|
||||
assert!(v.iter().all(|&x| x < 10));
|
||||
assert!(!v.iter().all(|&x| x % 2 == 0));
|
||||
assert!(!v.iter().all(|&x| x > 100));
|
||||
@ -377,7 +377,7 @@ fn test_all() {
|
||||
|
||||
#[test]
|
||||
fn test_any() {
|
||||
let v: Box<&[int]> = box &[1i, 2, 3, 4, 5];
|
||||
let v: Box<[int]> = box [1i, 2, 3, 4, 5];
|
||||
assert!(v.iter().any(|&x| x < 10));
|
||||
assert!(v.iter().any(|&x| x % 2 == 0));
|
||||
assert!(!v.iter().any(|&x| x > 100));
|
||||
|
@ -193,6 +193,8 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
|
||||
true
|
||||
}
|
||||
|
||||
// NOTE: remove after snapshot
|
||||
#[cfg(stage0)]
|
||||
fn visit_estr_fixed(&mut self, n: uint,
|
||||
sz: uint,
|
||||
align: uint) -> bool {
|
||||
@ -237,6 +239,7 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
|
||||
true
|
||||
}
|
||||
|
||||
#[cfg(stage0)]
|
||||
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
|
||||
mtbl: uint, inner: *const TyDesc) -> bool {
|
||||
self.align(align);
|
||||
@ -246,6 +249,16 @@ impl<V:TyVisitor + MovePtr> TyVisitor for MovePtrAdaptor<V> {
|
||||
self.bump(sz);
|
||||
true
|
||||
}
|
||||
#[cfg(not(stage0))]
|
||||
fn visit_evec_fixed(&mut self, n: uint, sz: uint, align: uint,
|
||||
inner: *const TyDesc) -> bool {
|
||||
self.align(align);
|
||||
if ! self.inner.visit_evec_fixed(n, sz, align, inner) {
|
||||
return false;
|
||||
}
|
||||
self.bump(sz);
|
||||
true
|
||||
}
|
||||
|
||||
fn visit_enter_rec(&mut self, n_fields: uint, sz: uint, align: uint) -> bool {
|
||||
self.align(align);
|
||||
|
@ -275,6 +275,8 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
|
||||
}
|
||||
|
||||
// Type no longer exists, vestigial function.
|
||||
// NOTE: remove after snapshot
|
||||
#[cfg(stage0)]
|
||||
fn visit_estr_fixed(&mut self, _n: uint, _sz: uint,
|
||||
_align: uint) -> bool { fail!(); }
|
||||
|
||||
@ -328,6 +330,8 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
// NOTE: remove after snapshot
|
||||
#[cfg(stage0)]
|
||||
fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint,
|
||||
_: uint, inner: *const TyDesc) -> bool {
|
||||
let assumed_size = if sz == 0 { n } else { sz };
|
||||
@ -336,6 +340,16 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint,
|
||||
inner: *const TyDesc) -> bool {
|
||||
let assumed_size = if sz == 0 { n } else { sz };
|
||||
self.get::<()>(|this, b| {
|
||||
this.write_vec_range(b, assumed_size, inner)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
fn visit_enter_rec(&mut self, _n_fields: uint,
|
||||
_sz: uint, _align: uint) -> bool {
|
||||
try!(self, self.writer.write([b'{']));
|
||||
|
@ -112,7 +112,7 @@ impl Context {
|
||||
// the stack limit to 0 to make morestack never fail
|
||||
None => stack::record_rust_managed_stack_bounds(0, uint::MAX),
|
||||
}
|
||||
rust_swap_registers(out_regs, in_regs)
|
||||
rust_swap_registers(out_regs, in_regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1449,8 +1449,8 @@ mod biguint_tests {
|
||||
|
||||
#[test]
|
||||
fn test_cmp() {
|
||||
let data: Vec<BigUint> = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ]
|
||||
.iter().map(|v| BigUint::from_slice(*v)).collect();
|
||||
let data: [&[_], ..7] = [ &[], &[1], &[2], &[-1], &[0, 1], &[2, 1], &[1, 1, 1] ];
|
||||
let data: Vec<BigUint> = data.iter().map(|v| BigUint::from_slice(*v)).collect();
|
||||
for (i, ni) in data.iter().enumerate() {
|
||||
for (j0, nj) in data.slice(i, data.len()).iter().enumerate() {
|
||||
let j = j0 + i;
|
||||
@ -2311,7 +2311,7 @@ mod bigint_tests {
|
||||
|
||||
#[test]
|
||||
fn test_cmp() {
|
||||
let vs = [ &[2 as BigDigit], &[1, 1], &[2, 1], &[1, 1, 1] ];
|
||||
let vs: [&[BigDigit], ..4] = [ &[2 as BigDigit], &[1, 1], &[2, 1], &[1, 1, 1] ];
|
||||
let mut nums = Vec::new();
|
||||
for s in vs.iter().rev() {
|
||||
nums.push(BigInt::from_slice(Minus, *s));
|
||||
|
@ -13,7 +13,6 @@
|
||||
use core::prelude::*;
|
||||
use core::iter::{range_step, Repeat};
|
||||
use core::slice::raw;
|
||||
use core::mem;
|
||||
|
||||
use {Rng, SeedableRng, Rand};
|
||||
|
||||
@ -46,6 +45,7 @@ static EMPTY: IsaacRng = IsaacRng {
|
||||
};
|
||||
|
||||
impl IsaacRng {
|
||||
|
||||
/// Create an ISAAC random number generator using the default
|
||||
/// fixed seed.
|
||||
pub fn new_unseeded() -> IsaacRng {
|
||||
@ -225,7 +225,7 @@ impl Rand for IsaacRng {
|
||||
let ptr = ret.rsl.as_mut_ptr();
|
||||
|
||||
raw::mut_buf_as_slice(ptr as *mut u8,
|
||||
mem::size_of_val(&ret.rsl), |slice| {
|
||||
(RAND_SIZE*4) as uint, |slice| {
|
||||
other.fill_bytes(slice);
|
||||
})
|
||||
}
|
||||
@ -456,7 +456,7 @@ impl Rand for Isaac64Rng {
|
||||
let ptr = ret.rsl.as_mut_ptr();
|
||||
|
||||
raw::mut_buf_as_slice(ptr as *mut u8,
|
||||
mem::size_of_val(&ret.rsl), |slice| {
|
||||
(RAND_SIZE_64*8) as uint, |slice| {
|
||||
other.fill_bytes(slice);
|
||||
})
|
||||
}
|
||||
@ -497,7 +497,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_seeded() {
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
assert!(order::equals(ra.gen_ascii_chars().take(100),
|
||||
@ -505,7 +505,7 @@ mod test {
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_seeded() {
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
assert!(order::equals(ra.gen_ascii_chars().take(100),
|
||||
@ -537,7 +537,7 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_rng_32_true_values() {
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = Vec::from_fn(10, |_| ra.next_u32());
|
||||
@ -545,7 +545,7 @@ mod test {
|
||||
vec!(2558573138, 873787463, 263499565, 2103644246, 3595684709,
|
||||
4203127393, 264982119, 2765226902, 2737944514, 3900253796));
|
||||
|
||||
let seed = &[12345, 67890, 54321, 9876];
|
||||
let seed: &[_] = &[12345, 67890, 54321, 9876];
|
||||
let mut rb: IsaacRng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in range(0u, 10000) { rb.next_u32(); }
|
||||
@ -557,7 +557,7 @@ mod test {
|
||||
}
|
||||
#[test]
|
||||
fn test_rng_64_true_values() {
|
||||
let seed = &[1, 23, 456, 7890, 12345];
|
||||
let seed: &[_] = &[1, 23, 456, 7890, 12345];
|
||||
let mut ra: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// Regression test that isaac is actually using the above vector
|
||||
let v = Vec::from_fn(10, |_| ra.next_u64());
|
||||
@ -567,7 +567,7 @@ mod test {
|
||||
4469761996653280935, 15552757044682284409, 6860251611068737823,
|
||||
13722198873481261842));
|
||||
|
||||
let seed = &[12345, 67890, 54321, 9876];
|
||||
let seed: &[_] = &[12345, 67890, 54321, 9876];
|
||||
let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
|
||||
// skip forward to the 10000th number
|
||||
for _ in range(0u, 10000) { rb.next_u64(); }
|
||||
|
@ -309,7 +309,8 @@ pub trait SeedableRng<Seed>: Rng {
|
||||
/// ```rust
|
||||
/// use std::rand::{Rng, SeedableRng, StdRng};
|
||||
///
|
||||
/// let mut rng: StdRng = SeedableRng::from_seed(&[1, 2, 3, 4]);
|
||||
/// let seed: &[_] = &[1, 2, 3, 4];
|
||||
/// let mut rng: StdRng = SeedableRng::from_seed(seed);
|
||||
/// println!("{}", rng.gen::<f64>());
|
||||
/// rng.reseed([5, 6, 7, 8]);
|
||||
/// println!("{}", rng.gen::<f64>());
|
||||
@ -323,7 +324,8 @@ pub trait SeedableRng<Seed>: Rng {
|
||||
/// ```rust
|
||||
/// use std::rand::{Rng, SeedableRng, StdRng};
|
||||
///
|
||||
/// let mut rng: StdRng = SeedableRng::from_seed(&[1, 2, 3, 4]);
|
||||
/// let seed: &[_] = &[1, 2, 3, 4];
|
||||
/// let mut rng: StdRng = SeedableRng::from_seed(seed);
|
||||
/// println!("{}", rng.gen::<f64>());
|
||||
/// ```
|
||||
fn from_seed(seed: Seed) -> Self;
|
||||
|
@ -96,7 +96,8 @@ impl Writer for SeekableMemWriter {
|
||||
let (left, right) = if cap <= buf.len() {
|
||||
(buf.slice_to(cap), buf.slice_from(cap))
|
||||
} else {
|
||||
(buf, &[])
|
||||
let result: (_, &[_]) = (buf, &[]);
|
||||
result
|
||||
};
|
||||
|
||||
// Do the necessary writes
|
||||
@ -142,24 +143,29 @@ mod tests {
|
||||
writer.write([1, 2, 3]).unwrap();
|
||||
writer.write([4, 5, 6, 7]).unwrap();
|
||||
assert_eq!(writer.tell(), Ok(8));
|
||||
assert_eq!(writer.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
|
||||
assert_eq!(writer.get_ref(), b);
|
||||
|
||||
writer.seek(0, io::SeekSet).unwrap();
|
||||
assert_eq!(writer.tell(), Ok(0));
|
||||
writer.write([3, 4]).unwrap();
|
||||
assert_eq!(writer.get_ref(), &[3, 4, 2, 3, 4, 5, 6, 7]);
|
||||
let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
|
||||
assert_eq!(writer.get_ref(), b);
|
||||
|
||||
writer.seek(1, io::SeekCur).unwrap();
|
||||
writer.write([0, 1]).unwrap();
|
||||
assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 7]);
|
||||
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
|
||||
assert_eq!(writer.get_ref(), b);
|
||||
|
||||
writer.seek(-1, io::SeekEnd).unwrap();
|
||||
writer.write([1, 2]).unwrap();
|
||||
assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2]);
|
||||
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
|
||||
assert_eq!(writer.get_ref(), b);
|
||||
|
||||
writer.seek(1, io::SeekEnd).unwrap();
|
||||
writer.write([1]).unwrap();
|
||||
assert_eq!(writer.get_ref(), &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]);
|
||||
let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
|
||||
assert_eq!(writer.get_ref(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -34,7 +34,6 @@ register_diagnostics!(
|
||||
E0015,
|
||||
E0016,
|
||||
E0017,
|
||||
E0018,
|
||||
E0019,
|
||||
E0020,
|
||||
E0021,
|
||||
@ -53,7 +52,6 @@ register_diagnostics!(
|
||||
E0034,
|
||||
E0035,
|
||||
E0036,
|
||||
E0037,
|
||||
E0038,
|
||||
E0039,
|
||||
E0040,
|
||||
@ -80,8 +78,6 @@ register_diagnostics!(
|
||||
E0061,
|
||||
E0062,
|
||||
E0063,
|
||||
E0064,
|
||||
E0065,
|
||||
E0066,
|
||||
E0067,
|
||||
E0068,
|
||||
@ -127,8 +123,6 @@ register_diagnostics!(
|
||||
E0108,
|
||||
E0109,
|
||||
E0110,
|
||||
E0111,
|
||||
E0112,
|
||||
E0113,
|
||||
E0114,
|
||||
E0115,
|
||||
|
@ -477,13 +477,14 @@ fn mk_test_descs(cx: &TestCtxt) -> Gc<ast::Expr> {
|
||||
|
||||
box(GC) ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ExprVstore(box(GC) ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ExprVec(cx.testfns.iter().map(|test| {
|
||||
mk_test_desc_and_fn_rec(cx, test)
|
||||
node: ast::ExprAddrOf(ast::MutImmutable,
|
||||
box(GC) ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
node: ast::ExprVec(cx.testfns.iter().map(|test| {
|
||||
mk_test_desc_and_fn_rec(cx, test)
|
||||
}).collect()),
|
||||
span: DUMMY_SP,
|
||||
}, ast::ExprVstoreSlice),
|
||||
}),
|
||||
span: DUMMY_SP,
|
||||
}
|
||||
}
|
||||
|
@ -1240,18 +1240,8 @@ impl LintPass for UnnecessaryAllocation {
|
||||
}
|
||||
|
||||
fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
||||
// Warn if string and vector literals with sigils, or boxing expressions,
|
||||
// are immediately borrowed.
|
||||
// Warn if boxing expressions are immediately borrowed.
|
||||
let allocation = match e.node {
|
||||
ast::ExprVstore(e2, ast::ExprVstoreUniq) => {
|
||||
match e2.node {
|
||||
ast::ExprLit(lit) if ast_util::lit_is_str(lit) => {
|
||||
VectorAllocation
|
||||
}
|
||||
ast::ExprVec(..) => VectorAllocation,
|
||||
_ => return
|
||||
}
|
||||
}
|
||||
ast::ExprUnary(ast::UnUniq, _) |
|
||||
ast::ExprUnary(ast::UnBox, _) => BoxAllocation,
|
||||
|
||||
@ -1261,19 +1251,19 @@ impl LintPass for UnnecessaryAllocation {
|
||||
match cx.tcx.adjustments.borrow().find(&e.id) {
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
ty::AutoDerefRef(ty::AutoDerefRef { autoref, .. }) => {
|
||||
ty::AutoDerefRef(ty::AutoDerefRef { ref autoref, .. }) => {
|
||||
match (allocation, autoref) {
|
||||
(VectorAllocation, Some(ty::AutoBorrowVec(..))) => {
|
||||
(VectorAllocation, &Some(ty::AutoPtr(_, _, None))) => {
|
||||
cx.span_lint(UNNECESSARY_ALLOCATION, e.span,
|
||||
"unnecessary allocation, the sigil can be removed");
|
||||
}
|
||||
(BoxAllocation,
|
||||
Some(ty::AutoPtr(_, ast::MutImmutable))) => {
|
||||
&Some(ty::AutoPtr(_, ast::MutImmutable, None))) => {
|
||||
cx.span_lint(UNNECESSARY_ALLOCATION, e.span,
|
||||
"unnecessary allocation, use & instead");
|
||||
}
|
||||
(BoxAllocation,
|
||||
Some(ty::AutoPtr(_, ast::MutMutable))) => {
|
||||
&Some(ty::AutoPtr(_, ast::MutMutable, None))) => {
|
||||
cx.span_lint(UNNECESSARY_ALLOCATION, e.span,
|
||||
"unnecessary allocation, use &mut instead");
|
||||
}
|
||||
@ -1566,6 +1556,9 @@ declare_lint!(pub UNKNOWN_CRATE_TYPE, Deny,
|
||||
declare_lint!(pub VARIANT_SIZE_DIFFERENCE, Allow,
|
||||
"detects enums with widely varying variant sizes")
|
||||
|
||||
declare_lint!(pub TRANSMUTE_FAT_PTR, Allow,
|
||||
"detects transmutes of fat pointers")
|
||||
|
||||
/// Does nothing as a lint pass, but registers some `Lint`s
|
||||
/// which are used by other parts of the compiler.
|
||||
pub struct HardwiredLints;
|
||||
|
@ -377,9 +377,9 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
|
||||
return ty::mk_rptr(st.tcx, r, mt);
|
||||
}
|
||||
'V' => {
|
||||
let mt = parse_mt(st, |x,y| conv(x,y));
|
||||
let t = parse_ty(st, |x,y| conv(x,y));
|
||||
let sz = parse_size(st);
|
||||
return ty::mk_vec(st.tcx, mt, sz);
|
||||
return ty::mk_vec(st.tcx, t, sz);
|
||||
}
|
||||
'v' => {
|
||||
return ty::mk_str(st.tcx);
|
||||
|
@ -254,9 +254,9 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
|
||||
enc_region(w, cx, r);
|
||||
enc_mt(w, cx, mt);
|
||||
}
|
||||
ty::ty_vec(mt, sz) => {
|
||||
ty::ty_vec(t, sz) => {
|
||||
mywrite!(w, "V");
|
||||
enc_mt(w, cx, mt);
|
||||
enc_ty(w, cx, t);
|
||||
mywrite!(w, "/");
|
||||
match sz {
|
||||
Some(n) => mywrite!(w, "{}|", n),
|
||||
@ -292,6 +292,9 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
|
||||
ty::ty_err => {
|
||||
mywrite!(w, "e");
|
||||
}
|
||||
ty::ty_open(_) => {
|
||||
cx.diag.handler().bug("unexpected type in enc_sty (ty_open)");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -495,25 +495,7 @@ impl tr for def::Def {
|
||||
}
|
||||
|
||||
// ______________________________________________________________________
|
||||
// Encoding and decoding of adjustment information
|
||||
|
||||
impl tr for ty::AutoDerefRef {
|
||||
fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef {
|
||||
ty::AutoDerefRef {
|
||||
autoderefs: self.autoderefs,
|
||||
autoref: match self.autoref {
|
||||
Some(ref autoref) => Some(autoref.tr(xcx)),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl tr for ty::AutoRef {
|
||||
fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::AutoRef {
|
||||
self.map_region(|r| r.tr(xcx))
|
||||
}
|
||||
}
|
||||
// Encoding and decoding of ancillary information
|
||||
|
||||
impl tr for ty::Region {
|
||||
fn tr(&self, xcx: &ExtendedDecodeContext) -> ty::Region {
|
||||
@ -961,6 +943,9 @@ trait rbml_writer_helpers {
|
||||
pty: ty::Polytype);
|
||||
fn emit_substs(&mut self, ecx: &e::EncodeContext, substs: &subst::Substs);
|
||||
fn emit_auto_adjustment(&mut self, ecx: &e::EncodeContext, adj: &ty::AutoAdjustment);
|
||||
fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef);
|
||||
fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef);
|
||||
fn emit_unsize_kind(&mut self, ecx: &e::EncodeContext, uk: &ty::UnsizeKind);
|
||||
}
|
||||
|
||||
impl<'a> rbml_writer_helpers for Encoder<'a> {
|
||||
@ -1035,16 +1020,91 @@ impl<'a> rbml_writer_helpers for Encoder<'a> {
|
||||
|
||||
ty::AutoDerefRef(ref auto_deref_ref) => {
|
||||
this.emit_enum_variant("AutoDerefRef", 1, 1, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| auto_deref_ref.encode(this))
|
||||
this.emit_enum_variant_arg(0,
|
||||
|this| Ok(this.emit_auto_deref_ref(ecx, auto_deref_ref)))
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ty::AutoObject(store, b, def_id, ref substs) => {
|
||||
this.emit_enum_variant("AutoObject", 2, 4, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| store.encode(this));
|
||||
this.emit_enum_variant_arg(1, |this| b.encode(this));
|
||||
this.emit_enum_variant_arg(2, |this| def_id.encode(this));
|
||||
this.emit_enum_variant_arg(3, |this| Ok(this.emit_substs(ecx, substs)))
|
||||
fn emit_autoref(&mut self, ecx: &e::EncodeContext, autoref: &ty::AutoRef) {
|
||||
use serialize::Encoder;
|
||||
|
||||
self.emit_enum("AutoRef", |this| {
|
||||
match autoref {
|
||||
&ty::AutoPtr(r, m, None) => {
|
||||
this.emit_enum_variant("AutoPtr", 0, 3, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| r.encode(this));
|
||||
this.emit_enum_variant_arg(1, |this| m.encode(this));
|
||||
this.emit_enum_variant_arg(2,
|
||||
|this| this.emit_option(|this| this.emit_option_none()))
|
||||
})
|
||||
}
|
||||
&ty::AutoPtr(r, m, Some(box ref a)) => {
|
||||
this.emit_enum_variant("AutoPtr", 0, 3, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| r.encode(this));
|
||||
this.emit_enum_variant_arg(1, |this| m.encode(this));
|
||||
this.emit_enum_variant_arg(2, |this| this.emit_option(
|
||||
|this| this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a)))))
|
||||
})
|
||||
}
|
||||
&ty::AutoUnsize(ref uk) => {
|
||||
this.emit_enum_variant("AutoUnsize", 1, 1, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk)))
|
||||
})
|
||||
}
|
||||
&ty::AutoUnsizeUniq(ref uk) => {
|
||||
this.emit_enum_variant("AutoUnsizeUniq", 2, 1, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk)))
|
||||
})
|
||||
}
|
||||
&ty::AutoUnsafe(m) => {
|
||||
this.emit_enum_variant("AutoUnsafe", 3, 1, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| m.encode(this))
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn emit_auto_deref_ref(&mut self, ecx: &e::EncodeContext, auto_deref_ref: &ty::AutoDerefRef) {
|
||||
use serialize::Encoder;
|
||||
|
||||
self.emit_struct("AutoDerefRef", 2, |this| {
|
||||
this.emit_struct_field("autoderefs", 0, |this| auto_deref_ref.autoderefs.encode(this));
|
||||
this.emit_struct_field("autoref", 1, |this| {
|
||||
this.emit_option(|this| {
|
||||
match auto_deref_ref.autoref {
|
||||
None => this.emit_option_none(),
|
||||
Some(ref a) => this.emit_option_some(|this| Ok(this.emit_autoref(ecx, a))),
|
||||
}
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn emit_unsize_kind(&mut self, ecx: &e::EncodeContext, uk: &ty::UnsizeKind) {
|
||||
use serialize::Encoder;
|
||||
|
||||
self.emit_enum("UnsizeKind", |this| {
|
||||
match *uk {
|
||||
ty::UnsizeLength(len) => {
|
||||
this.emit_enum_variant("UnsizeLength", 0, 1, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| len.encode(this))
|
||||
})
|
||||
}
|
||||
ty::UnsizeStruct(box ref uk, idx) => {
|
||||
this.emit_enum_variant("UnsizeStruct", 1, 2, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| Ok(this.emit_unsize_kind(ecx, uk)));
|
||||
this.emit_enum_variant_arg(1, |this| idx.encode(this))
|
||||
})
|
||||
}
|
||||
ty::UnsizeVtable(b, def_id, ref substs) => {
|
||||
this.emit_enum_variant("UnsizeVtable", 2, 3, |this| {
|
||||
this.emit_enum_variant_arg(0, |this| b.encode(this));
|
||||
this.emit_enum_variant_arg(1, |this| def_id.encode(this));
|
||||
this.emit_enum_variant_arg(2, |this| Ok(this.emit_substs(ecx, substs)))
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -1227,9 +1287,30 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
||||
})
|
||||
}
|
||||
|
||||
for &adj in tcx.adjustments.borrow().find(&id).iter() {
|
||||
match *adj {
|
||||
ty::AutoDerefRef(adj) => {
|
||||
for &adjustment in tcx.adjustments.borrow().find(&id).iter() {
|
||||
match *adjustment {
|
||||
_ if ty::adjust_is_object(adjustment) => {
|
||||
let method_call = MethodCall::autoobject(id);
|
||||
for &method in tcx.method_map.borrow().find(&method_call).iter() {
|
||||
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
for &dr in tcx.vtable_map.borrow().find(&method_call).iter() {
|
||||
rbml_w.tag(c::tag_table_vtable_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr);
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
ty::AutoDerefRef(ref adj) => {
|
||||
assert!(!ty::adjust_is_object(adjustment));
|
||||
for autoderef in range(0, adj.autoderefs) {
|
||||
let method_call = MethodCall::autoderef(id, autoderef);
|
||||
for &method in tcx.method_map.borrow().find(&method_call).iter() {
|
||||
@ -1253,33 +1334,15 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::AutoObject(..) => {
|
||||
let method_call = MethodCall::autoobject(id);
|
||||
for &method in tcx.method_map.borrow().find(&method_call).iter() {
|
||||
rbml_w.tag(c::tag_table_method_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
encode_method_callee(ecx, rbml_w, method_call.adjustment, method)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
for &dr in tcx.vtable_map.borrow().find(&method_call).iter() {
|
||||
rbml_w.tag(c::tag_table_vtable_map, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
encode_vtable_res_with_key(ecx, rbml_w, method_call.adjustment, dr);
|
||||
})
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
assert!(!ty::adjust_is_object(adjustment));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
rbml_w.tag(c::tag_table_adjustments, |rbml_w| {
|
||||
rbml_w.id(id);
|
||||
rbml_w.tag(c::tag_table_val, |rbml_w| {
|
||||
rbml_w.emit_auto_adjustment(ecx, adj);
|
||||
rbml_w.emit_auto_adjustment(ecx, adjustment);
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -1321,6 +1384,9 @@ trait rbml_decoder_decoder_helpers {
|
||||
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment;
|
||||
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
|
||||
-> ty::UnboxedClosure;
|
||||
fn read_auto_deref_ref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef;
|
||||
fn read_autoref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoRef;
|
||||
fn read_unsize_kind(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnsizeKind;
|
||||
fn convert_def_id(&mut self,
|
||||
xcx: &ExtendedDecodeContext,
|
||||
source: DefIdSource,
|
||||
@ -1460,32 +1526,21 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||
|
||||
fn read_auto_adjustment(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoAdjustment {
|
||||
self.read_enum("AutoAdjustment", |this| {
|
||||
let variants = ["AutoAddEnv", "AutoDerefRef", "AutoObject"];
|
||||
let variants = ["AutoAddEnv", "AutoDerefRef"];
|
||||
this.read_enum_variant(variants, |this, i| {
|
||||
Ok(match i {
|
||||
0 => {
|
||||
let store: ty::TraitStore =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
|
||||
ty:: AutoAddEnv(store.tr(xcx))
|
||||
ty::AutoAddEnv(store.tr(xcx))
|
||||
}
|
||||
1 => {
|
||||
let auto_deref_ref: ty::AutoDerefRef =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
this.read_enum_variant_arg(0,
|
||||
|this| Ok(this.read_auto_deref_ref(xcx))).unwrap();
|
||||
|
||||
ty::AutoDerefRef(auto_deref_ref.tr(xcx))
|
||||
}
|
||||
2 => {
|
||||
let store: ty::TraitStore =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
let b: ty::BuiltinBounds =
|
||||
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
|
||||
let def_id: ast::DefId =
|
||||
this.read_enum_variant_arg(2, |this| Decodable::decode(this)).unwrap();
|
||||
let substs = this.read_enum_variant_arg(3, |this| Ok(this.read_substs(xcx)))
|
||||
.unwrap();
|
||||
|
||||
ty::AutoObject(store.tr(xcx), b, def_id.tr(xcx), substs)
|
||||
ty::AutoDerefRef(auto_deref_ref)
|
||||
}
|
||||
_ => fail!("bad enum variant for ty::AutoAdjustment")
|
||||
})
|
||||
@ -1493,6 +1548,111 @@ impl<'a> rbml_decoder_decoder_helpers for reader::Decoder<'a> {
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_auto_deref_ref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoDerefRef {
|
||||
self.read_struct("AutoDerefRef", 2, |this| {
|
||||
Ok(ty::AutoDerefRef {
|
||||
autoderefs: this.read_struct_field("autoderefs", 0, |this| {
|
||||
Decodable::decode(this)
|
||||
}).unwrap(),
|
||||
autoref: this.read_struct_field("autoref", 1, |this| {
|
||||
this.read_option(|this, b| {
|
||||
if b {
|
||||
Ok(Some(this.read_autoref(xcx)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
}).unwrap(),
|
||||
})
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_autoref(&mut self, xcx: &ExtendedDecodeContext) -> ty::AutoRef {
|
||||
self.read_enum("AutoRef", |this| {
|
||||
let variants = ["AutoPtr",
|
||||
"AutoUnsize",
|
||||
"AutoUnsizeUniq",
|
||||
"AutoUnsafe"];
|
||||
this.read_enum_variant(variants, |this, i| {
|
||||
Ok(match i {
|
||||
0 => {
|
||||
let r: ty::Region =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
let m: ast::Mutability =
|
||||
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
|
||||
let a: Option<Box<ty::AutoRef>> =
|
||||
this.read_enum_variant_arg(2, |this| this.read_option(|this, b| {
|
||||
if b {
|
||||
Ok(Some(box this.read_autoref(xcx)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})).unwrap();
|
||||
|
||||
ty::AutoPtr(r.tr(xcx), m, a)
|
||||
}
|
||||
1 => {
|
||||
let uk: ty::UnsizeKind =
|
||||
this.read_enum_variant_arg(0,
|
||||
|this| Ok(this.read_unsize_kind(xcx))).unwrap();
|
||||
|
||||
ty::AutoUnsize(uk)
|
||||
}
|
||||
2 => {
|
||||
let uk: ty::UnsizeKind =
|
||||
this.read_enum_variant_arg(0,
|
||||
|this| Ok(this.read_unsize_kind(xcx))).unwrap();
|
||||
|
||||
ty::AutoUnsizeUniq(uk)
|
||||
}
|
||||
3 => {
|
||||
let m: ast::Mutability =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
|
||||
ty::AutoUnsafe(m)
|
||||
}
|
||||
_ => fail!("bad enum variant for ty::AutoRef")
|
||||
})
|
||||
})
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_unsize_kind(&mut self, xcx: &ExtendedDecodeContext) -> ty::UnsizeKind {
|
||||
self.read_enum("UnsizeKind", |this| {
|
||||
let variants = ["UnsizeLength", "UnsizeStruct", "UnsizeVtable"];
|
||||
this.read_enum_variant(variants, |this, i| {
|
||||
Ok(match i {
|
||||
0 => {
|
||||
let len: uint =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
|
||||
ty::UnsizeLength(len)
|
||||
}
|
||||
1 => {
|
||||
let uk: ty::UnsizeKind =
|
||||
this.read_enum_variant_arg(0,
|
||||
|this| Ok(this.read_unsize_kind(xcx))).unwrap();
|
||||
let idx: uint =
|
||||
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
|
||||
|
||||
ty::UnsizeStruct(box uk, idx)
|
||||
}
|
||||
2 => {
|
||||
let b: ty::BuiltinBounds =
|
||||
this.read_enum_variant_arg(0, |this| Decodable::decode(this)).unwrap();
|
||||
let def_id: ast::DefId =
|
||||
this.read_enum_variant_arg(1, |this| Decodable::decode(this)).unwrap();
|
||||
let substs = this.read_enum_variant_arg(2,
|
||||
|this| Ok(this.read_substs(xcx))).unwrap();
|
||||
|
||||
ty::UnsizeVtable(b, def_id.tr(xcx), substs)
|
||||
}
|
||||
_ => fail!("bad enum variant for ty::UnsizeKind")
|
||||
})
|
||||
})
|
||||
}).unwrap()
|
||||
}
|
||||
|
||||
fn read_unboxed_closure(&mut self, xcx: &ExtendedDecodeContext)
|
||||
-> ty::UnboxedClosure {
|
||||
let closure_type = self.read_opaque(|this, doc| {
|
||||
|
@ -428,16 +428,15 @@ impl<'a> BorrowckCtxt<'a> {
|
||||
adj: &ty::AutoAdjustment)
|
||||
-> mc::cmt {
|
||||
let r = match *adj {
|
||||
ty::AutoAddEnv(..) | ty::AutoObject(..) => {
|
||||
// no autoderefs
|
||||
self.mc().cat_expr_unadjusted(expr)
|
||||
}
|
||||
|
||||
ty::AutoDerefRef(
|
||||
ty::AutoDerefRef {
|
||||
autoderefs: autoderefs, ..}) => {
|
||||
self.mc().cat_expr_autoderefd(expr, autoderefs)
|
||||
}
|
||||
ty::AutoAddEnv(..) => {
|
||||
// no autoderefs
|
||||
self.mc().cat_expr_unadjusted(expr)
|
||||
}
|
||||
};
|
||||
|
||||
match r {
|
||||
|
@ -465,7 +465,6 @@ impl<'a> CFGBuilder<'a> {
|
||||
ast::ExprCast(e, _) |
|
||||
ast::ExprUnary(_, e) |
|
||||
ast::ExprParen(e) |
|
||||
ast::ExprVstore(e, _) |
|
||||
ast::ExprField(e, _, _) => {
|
||||
self.straightline(expr, pred, [e])
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ fn check_item(v: &mut CheckCrateVisitor, it: &Item, _is_const: bool) {
|
||||
fn check_pat(v: &mut CheckCrateVisitor, p: &Pat, _is_const: bool) {
|
||||
fn is_str(e: &Expr) -> bool {
|
||||
match e.node {
|
||||
ExprVstore(expr, ExprVstoreUniq) => {
|
||||
ExprBox(_, expr) => {
|
||||
match expr.node {
|
||||
ExprLit(lit) => ast_util::lit_is_str(lit),
|
||||
_ => false,
|
||||
@ -169,8 +169,6 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
ExprVstore(_, ExprVstoreMutSlice) |
|
||||
ExprVstore(_, ExprVstoreSlice) |
|
||||
ExprVec(_) |
|
||||
ExprAddrOf(MutImmutable, _) |
|
||||
ExprParen(..) |
|
||||
@ -179,13 +177,14 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &Expr, is_const: bool) {
|
||||
ExprTup(..) |
|
||||
ExprRepeat(..) |
|
||||
ExprStruct(..) => { }
|
||||
ExprAddrOf(..) => {
|
||||
span_err!(v.tcx.sess, e.span, E0017,
|
||||
"references in constants may only refer to immutable values");
|
||||
},
|
||||
ExprVstore(_, ExprVstoreUniq) => {
|
||||
span_err!(v.tcx.sess, e.span, E0018,
|
||||
"cannot allocate vectors in constant expressions");
|
||||
ExprAddrOf(_, inner) => {
|
||||
match inner.node {
|
||||
// Mutable slices are allowed.
|
||||
ExprVec(_) => {}
|
||||
_ => span_err!(v.tcx.sess, e.span, E0017,
|
||||
"references in constants may only refer to immutable values")
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
_ => {
|
||||
|
@ -107,21 +107,19 @@ impl<'a> Visitor<bool> for CheckStaticVisitor<'a> {
|
||||
|
||||
match e.node {
|
||||
ast::ExprField(..) | ast::ExprVec(..) |
|
||||
ast::ExprBlock(..) | ast::ExprTup(..) |
|
||||
ast::ExprVstore(_, ast::ExprVstoreSlice) => {
|
||||
ast::ExprBlock(..) | ast::ExprTup(..) => {
|
||||
visit::walk_expr(self, e, is_const);
|
||||
}
|
||||
ast::ExprVstore(_, ast::ExprVstoreMutSlice) => {
|
||||
ast::ExprAddrOf(ast::MutMutable, _) => {
|
||||
span_err!(self.tcx.sess, e.span, E0020,
|
||||
"static items are not allowed to have mutable slices");
|
||||
},
|
||||
},
|
||||
ast::ExprUnary(ast::UnBox, _) => {
|
||||
span_err!(self.tcx.sess, e.span, E0021,
|
||||
"static items are not allowed to have managed pointers");
|
||||
}
|
||||
ast::ExprBox(..) |
|
||||
ast::ExprUnary(ast::UnUniq, _) |
|
||||
ast::ExprVstore(_, ast::ExprVstoreUniq) => {
|
||||
ast::ExprUnary(ast::UnUniq, _) => {
|
||||
span_err!(self.tcx.sess, e.span, E0022,
|
||||
"static items are not allowed to have custom pointers");
|
||||
}
|
||||
|
@ -206,14 +206,6 @@ impl<'a> ConstEvalVisitor<'a> {
|
||||
ast::ExprVec(ref es) =>
|
||||
join_all(es.iter().map(|e| self.classify(&**e))),
|
||||
|
||||
ast::ExprVstore(ref e, vstore) => {
|
||||
match vstore {
|
||||
ast::ExprVstoreSlice => self.classify(&**e),
|
||||
ast::ExprVstoreUniq |
|
||||
ast::ExprVstoreMutSlice => non_const
|
||||
}
|
||||
}
|
||||
|
||||
ast::ExprStruct(_, ref fs, None) => {
|
||||
let cs = fs.iter().map(|f| self.classify(&*f.expr));
|
||||
join_all(cs)
|
||||
@ -554,8 +546,6 @@ pub fn eval_const_expr_partial<T: ty::ExprTyProvider>(tcx: &T, e: &Expr)
|
||||
}
|
||||
}
|
||||
ExprLit(ref lit) => Ok(lit_to_const(&**lit)),
|
||||
// If we have a vstore, just keep going; it has to be a string
|
||||
ExprVstore(ref e, _) => eval_const_expr_partial(tcx, &**e),
|
||||
ExprParen(ref e) => eval_const_expr_partial(tcx, &**e),
|
||||
ExprBlock(ref block) => {
|
||||
match block.expr {
|
||||
|
@ -474,10 +474,6 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
|
||||
self.walk_captures(expr)
|
||||
}
|
||||
|
||||
ast::ExprVstore(ref base, _) => {
|
||||
self.consume_expr(&**base);
|
||||
}
|
||||
|
||||
ast::ExprBox(ref place, ref base) => {
|
||||
self.consume_expr(&**place);
|
||||
self.consume_expr(&**base);
|
||||
@ -672,11 +668,10 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
|
||||
None => { }
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
ty::AutoAddEnv(..) |
|
||||
ty::AutoObject(..) => {
|
||||
// Creating an object or closure consumes the
|
||||
// input and stores it into the resulting rvalue.
|
||||
debug!("walk_adjustment(AutoAddEnv|AutoObject)");
|
||||
ty::AutoAddEnv(..) => {
|
||||
// Creating a closure consumes the input and stores it
|
||||
// into the resulting rvalue.
|
||||
debug!("walk_adjustment(AutoAddEnv)");
|
||||
let cmt_unadjusted =
|
||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||
@ -735,42 +730,39 @@ impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
|
||||
fn walk_autoref(&mut self,
|
||||
expr: &ast::Expr,
|
||||
autoref: &ty::AutoRef,
|
||||
autoderefs: uint) {
|
||||
debug!("walk_autoref expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
|
||||
n: uint) {
|
||||
debug!("walk_autoref expr={}", expr.repr(self.tcx()));
|
||||
|
||||
// Match for unique trait coercions first, since we don't need the
|
||||
// call to cat_expr_autoderefd.
|
||||
match *autoref {
|
||||
ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) |
|
||||
ty::AutoUnsize(ty::UnsizeVtable(..)) => {
|
||||
assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
|
||||
AutoRefs, found: {}", n));
|
||||
let cmt_unadjusted =
|
||||
return_if_err!(self.mc.cat_expr_unadjusted(expr));
|
||||
self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let cmt_derefd = return_if_err!(
|
||||
self.mc.cat_expr_autoderefd(expr, autoderefs));
|
||||
|
||||
debug!("walk_autoref: cmt_derefd={}", cmt_derefd.repr(self.tcx()));
|
||||
self.mc.cat_expr_autoderefd(expr, n));
|
||||
debug!("walk_adjustment: cmt_derefd={}",
|
||||
cmt_derefd.repr(self.tcx()));
|
||||
|
||||
match *autoref {
|
||||
ty::AutoPtr(r, m) => {
|
||||
ty::AutoPtr(r, m, _) => {
|
||||
self.delegate.borrow(expr.id,
|
||||
expr.span,
|
||||
cmt_derefd,
|
||||
r,
|
||||
ty::BorrowKind::from_mutbl(m),
|
||||
AutoRef)
|
||||
AutoRef);
|
||||
}
|
||||
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
|
||||
let cmt_index = self.mc.cat_index(expr, cmt_derefd, autoderefs+1);
|
||||
self.delegate.borrow(expr.id,
|
||||
expr.span,
|
||||
cmt_index,
|
||||
r,
|
||||
ty::BorrowKind::from_mutbl(m),
|
||||
AutoRef)
|
||||
}
|
||||
ty::AutoBorrowObj(r, m) => {
|
||||
let cmt_deref = self.mc.cat_deref_obj(expr, cmt_derefd);
|
||||
self.delegate.borrow(expr.id,
|
||||
expr.span,
|
||||
cmt_deref,
|
||||
r,
|
||||
ty::BorrowKind::from_mutbl(m),
|
||||
AutoRef)
|
||||
}
|
||||
ty::AutoUnsafe(_) => {}
|
||||
ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,7 +92,7 @@ impl<'a> IntrinsicCheckingVisitor<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_transmute(&self, span: Span, from: ty::t, to: ty::t) {
|
||||
fn check_transmute(&self, span: Span, from: ty::t, to: ty::t, id: ast::NodeId) {
|
||||
if type_size_is_affected_by_type_parameters(self.tcx, from) {
|
||||
span_err!(self.tcx.sess, span, E0139,
|
||||
"cannot transmute from a type that contains type parameters");
|
||||
@ -106,6 +106,7 @@ impl<'a> IntrinsicCheckingVisitor<'a> {
|
||||
span: span,
|
||||
from: from,
|
||||
to: to,
|
||||
id: id,
|
||||
};
|
||||
self.tcx.transmute_restrictions.borrow_mut().push(restriction);
|
||||
}
|
||||
@ -123,7 +124,7 @@ impl<'a> Visitor<()> for IntrinsicCheckingVisitor<'a> {
|
||||
if bare_fn_ty.abi == RustIntrinsic => {
|
||||
let from = *bare_fn_ty.sig.inputs.get(0);
|
||||
let to = bare_fn_ty.sig.output;
|
||||
self.check_transmute(expr.span, from, to);
|
||||
self.check_transmute(expr.span, from, to, expr.id);
|
||||
}
|
||||
_ => {
|
||||
self.tcx
|
||||
|
@ -405,14 +405,27 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||
"repeated element will be copied");
|
||||
}
|
||||
}
|
||||
ExprAssign(ref lhs, _) |
|
||||
ExprAssignOp(_, ref lhs, _) => {
|
||||
let lhs_ty = ty::expr_ty(cx.tcx, &**lhs);
|
||||
if !ty::type_is_sized(cx.tcx, lhs_ty) {
|
||||
cx.tcx.sess.span_err(lhs.span, "dynamically sized type on lhs of assignment");
|
||||
}
|
||||
}
|
||||
ExprStruct(..) => {
|
||||
let e_ty = ty::expr_ty(cx.tcx, e);
|
||||
if !ty::type_is_sized(cx.tcx, e_ty) {
|
||||
cx.tcx.sess.span_err(e.span, "trying to initialise a dynamically sized struct");
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Search for auto-adjustments to find trait coercions.
|
||||
match cx.tcx.adjustments.borrow().find(&e.id) {
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
ty::AutoObject(..) => {
|
||||
match adjustment {
|
||||
adj if ty::adjust_is_object(adj) => {
|
||||
let source_ty = ty::expr_ty(cx.tcx, e);
|
||||
let target_ty = ty::expr_ty_adjusted(cx.tcx, e);
|
||||
let method_call = MethodCall {
|
||||
@ -425,8 +438,7 @@ pub fn check_expr(cx: &mut Context, e: &Expr) {
|
||||
e.span,
|
||||
method_call);
|
||||
}
|
||||
ty::AutoAddEnv(..) |
|
||||
ty::AutoDerefRef(..) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
|
@ -511,7 +511,7 @@ fn visit_expr(ir: &mut IrMaps, expr: &Expr) {
|
||||
}
|
||||
|
||||
// otherwise, live nodes are not required:
|
||||
ExprIndex(..) | ExprField(..) | ExprVstore(..) | ExprVec(..) |
|
||||
ExprIndex(..) | ExprField(..) | ExprVec(..) |
|
||||
ExprCall(..) | ExprMethodCall(..) | ExprTup(..) |
|
||||
ExprBinary(..) | ExprAddrOf(..) |
|
||||
ExprCast(..) | ExprUnary(..) | ExprBreak(_) |
|
||||
@ -1119,10 +1119,6 @@ impl<'a> Liveness<'a> {
|
||||
|
||||
// Uninteresting cases: just propagate in rev exec order
|
||||
|
||||
ExprVstore(ref expr, _) => {
|
||||
self.propagate_through_expr(&**expr, succ)
|
||||
}
|
||||
|
||||
ExprVec(ref exprs) => {
|
||||
self.propagate_through_exprs(exprs.as_slice(), succ)
|
||||
}
|
||||
@ -1449,8 +1445,7 @@ fn check_expr(this: &mut Liveness, expr: &Expr) {
|
||||
// no correctness conditions related to liveness
|
||||
ExprCall(..) | ExprMethodCall(..) | ExprIf(..) | ExprMatch(..) |
|
||||
ExprWhile(..) | ExprLoop(..) | ExprIndex(..) | ExprField(..) |
|
||||
ExprVstore(..) | ExprVec(..) | ExprTup(..) |
|
||||
ExprBinary(..) |
|
||||
ExprVec(..) | ExprTup(..) | ExprBinary(..) |
|
||||
ExprCast(..) | ExprUnary(..) | ExprRet(..) | ExprBreak(..) |
|
||||
ExprAgain(..) | ExprLit(_) | ExprBlock(..) |
|
||||
ExprMac(..) | ExprAddrOf(..) | ExprStruct(..) | ExprRepeat(..) |
|
||||
|
@ -205,7 +205,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
|
||||
Some(deref_interior(InteriorField(PositionalField(0))))
|
||||
}
|
||||
|
||||
ty::ty_vec(_, Some(_)) => {
|
||||
ty::ty_vec(_, _) | ty::ty_str => {
|
||||
Some(deref_interior(InteriorElement(element_kind(t))))
|
||||
}
|
||||
|
||||
@ -214,11 +214,12 @@ pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
|
||||
}
|
||||
|
||||
pub fn deref_kind(tcx: &ty::ctxt, t: ty::t) -> deref_kind {
|
||||
debug!("deref_kind {}", ty_to_string(tcx, t));
|
||||
match opt_deref_kind(t) {
|
||||
Some(k) => k,
|
||||
None => {
|
||||
tcx.sess.bug(
|
||||
format!("deref_cat() invoked on non-derefable type {}",
|
||||
format!("deref_kind() invoked on non-derefable type {}",
|
||||
ty_to_string(tcx, t)).as_slice());
|
||||
}
|
||||
}
|
||||
@ -411,13 +412,6 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
ty::AutoObject(..) => {
|
||||
// Implicitly cast a concrete object to trait object.
|
||||
// Result is an rvalue.
|
||||
let expr_ty = if_ok!(self.expr_ty_adjusted(expr));
|
||||
Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
|
||||
}
|
||||
|
||||
ty::AutoAddEnv(..) => {
|
||||
// Convert a bare fn to a closure by adding NULL env.
|
||||
// Result is an rvalue.
|
||||
@ -485,7 +479,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
}
|
||||
None => {
|
||||
let base_cmt = if_ok!(self.cat_expr(&**base));
|
||||
Ok(self.cat_index(expr, base_cmt, 0))
|
||||
Ok(self.cat_index(expr, base_cmt))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -504,7 +498,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
ast::ExprFnBlock(..) | ast::ExprProc(..) |
|
||||
ast::ExprUnboxedFn(..) | ast::ExprRet(..) |
|
||||
ast::ExprUnary(..) |
|
||||
ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) |
|
||||
ast::ExprMethodCall(..) | ast::ExprCast(..) |
|
||||
ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
|
||||
ast::ExprBinary(..) | ast::ExprWhile(..) |
|
||||
ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
|
||||
@ -703,7 +697,10 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
-> cmt {
|
||||
match self.typer.temporary_scope(id) {
|
||||
Some(scope) => {
|
||||
self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty)
|
||||
match ty::get(expr_ty).sty {
|
||||
ty::ty_vec(_, Some(0)) => self.cat_rvalue(id, span, ty::ReStatic, expr_ty),
|
||||
_ => self.cat_rvalue(id, span, ty::ReScope(scope), expr_ty)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
self.cat_rvalue(id, span, ty::ReStatic, expr_ty)
|
||||
@ -751,10 +748,11 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
implicit: bool)
|
||||
-> cmt {
|
||||
let adjustment = match self.typer.adjustments().borrow().find(&node.id()) {
|
||||
Some(&ty::AutoObject(..)) => typeck::AutoObject,
|
||||
Some(adj) if ty::adjust_is_object(adj) => typeck::AutoObject,
|
||||
_ if deref_cnt != 0 => typeck::AutoDeref(deref_cnt),
|
||||
_ => typeck::NoAdjustment
|
||||
};
|
||||
|
||||
let method_call = typeck::MethodCall {
|
||||
expr_id: node.id(),
|
||||
adjustment: adjustment
|
||||
@ -820,13 +818,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
|
||||
pub fn cat_index<N:ast_node>(&self,
|
||||
elt: &N,
|
||||
mut base_cmt: cmt,
|
||||
derefs: uint)
|
||||
mut base_cmt: cmt)
|
||||
-> cmt {
|
||||
//! Creates a cmt for an indexing operation (`[]`); this
|
||||
//! indexing operation may occurs as part of an
|
||||
//! AutoBorrowVec, which when converting a `~[]` to an `&[]`
|
||||
//! effectively takes the address of the 0th element.
|
||||
//! Creates a cmt for an indexing operation (`[]`).
|
||||
//!
|
||||
//! One subtle aspect of indexing that may not be
|
||||
//! immediately obvious: for anything other than a fixed-length
|
||||
@ -839,20 +833,9 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
//! cmt containing both this deref and the indexing,
|
||||
//! presuming that `base_cmt` is not of fixed-length type.
|
||||
//!
|
||||
//! In the event that a deref is needed, the "deref count"
|
||||
//! is taken from the parameter `derefs`. See the comment
|
||||
//! on the def'n of `root_map_key` in borrowck/mod.rs
|
||||
//! for more details about deref counts; the summary is
|
||||
//! that `derefs` should be 0 for an explicit indexing
|
||||
//! operation and N+1 for an indexing that is part of
|
||||
//! an auto-adjustment, where N is the number of autoderefs
|
||||
//! in that adjustment.
|
||||
//!
|
||||
//! # Parameters
|
||||
//! - `elt`: the AST node being indexed
|
||||
//! - `base_cmt`: the cmt of `elt`
|
||||
//! - `derefs`: the deref number to be used for
|
||||
//! the implicit index deref, if any (see above)
|
||||
|
||||
let method_call = typeck::MethodCall::expr(elt.id());
|
||||
let method_ty = self.typer.node_method_ty(method_call);
|
||||
@ -865,7 +848,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
}
|
||||
None => {
|
||||
match ty::array_element_ty(base_cmt.ty) {
|
||||
Some(ref mt) => mt.ty,
|
||||
Some(ty) => ty,
|
||||
None => {
|
||||
self.tcx().sess.span_bug(
|
||||
elt.span(),
|
||||
@ -876,30 +859,8 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
}
|
||||
};
|
||||
|
||||
return match deref_kind(self.tcx(), base_cmt.ty) {
|
||||
deref_ptr(ptr) => {
|
||||
// for unique ptrs, we inherit mutability from the
|
||||
// owning reference.
|
||||
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);
|
||||
|
||||
// the deref is explicit in the resulting cmt
|
||||
let deref_cmt = Rc::new(cmt_ {
|
||||
id:elt.id(),
|
||||
span:elt.span(),
|
||||
cat:cat_deref(base_cmt.clone(), derefs, ptr),
|
||||
mutbl:m,
|
||||
ty:element_ty
|
||||
});
|
||||
|
||||
interior(elt, deref_cmt, base_cmt.ty, m.inherit(), element_ty)
|
||||
}
|
||||
|
||||
deref_interior(_) => {
|
||||
// fixed-length vectors have no deref
|
||||
let m = base_cmt.mutbl.inherit();
|
||||
interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty)
|
||||
}
|
||||
};
|
||||
let m = base_cmt.mutbl.inherit();
|
||||
return interior(elt, base_cmt.clone(), base_cmt.ty, m, element_ty);
|
||||
|
||||
fn interior<N: ast_node>(elt: &N,
|
||||
of_cmt: cmt,
|
||||
@ -917,6 +878,37 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
}
|
||||
}
|
||||
|
||||
// Takes either a vec or a reference to a vec and returns the cmt for the
|
||||
// underlying vec.
|
||||
fn deref_vec<N:ast_node>(&self,
|
||||
elt: &N,
|
||||
base_cmt: cmt)
|
||||
-> cmt {
|
||||
match deref_kind(self.tcx(), base_cmt.ty) {
|
||||
deref_ptr(ptr) => {
|
||||
// for unique ptrs, we inherit mutability from the
|
||||
// owning reference.
|
||||
let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);
|
||||
|
||||
// the deref is explicit in the resulting cmt
|
||||
Rc::new(cmt_ {
|
||||
id:elt.id(),
|
||||
span:elt.span(),
|
||||
cat:cat_deref(base_cmt.clone(), 0, ptr),
|
||||
mutbl:m,
|
||||
ty: match ty::deref(base_cmt.ty, false) {
|
||||
Some(mt) => mt.ty,
|
||||
None => self.tcx().sess.bug("Found non-derefable type")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
deref_interior(_) => {
|
||||
base_cmt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cat_slice_pattern(&self,
|
||||
vec_cmt: cmt,
|
||||
slice_pat: &ast::Pat)
|
||||
@ -935,7 +927,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
let (slice_mutbl, slice_r) = vec_slice_info(self.tcx(),
|
||||
slice_pat,
|
||||
slice_ty);
|
||||
let cmt_slice = self.cat_index(slice_pat, vec_cmt, 0);
|
||||
let cmt_slice = self.cat_index(slice_pat, self.deref_vec(slice_pat, vec_cmt));
|
||||
return Ok((cmt_slice, slice_mutbl, slice_r));
|
||||
|
||||
fn vec_slice_info(tcx: &ty::ctxt,
|
||||
@ -951,7 +943,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
|
||||
match ty::get(slice_ty).sty {
|
||||
ty::ty_rptr(r, ref mt) => match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(slice_mt, None) => (slice_mt.mutbl, r),
|
||||
ty::ty_vec(_, None) => (mt.mutbl, r),
|
||||
_ => vec_slice_info(tcx, pat, mt.ty),
|
||||
},
|
||||
|
||||
@ -1143,7 +1135,7 @@ impl<'t,TYPER:Typer> MemCategorizationContext<'t,TYPER> {
|
||||
}
|
||||
|
||||
ast::PatVec(ref before, slice, ref after) => {
|
||||
let elt_cmt = self.cat_index(pat, cmt, 0);
|
||||
let elt_cmt = self.cat_index(pat, self.deref_vec(pat, cmt));
|
||||
for before_pat in before.iter() {
|
||||
if_ok!(self.cat_pattern(elt_cmt.clone(), &**before_pat,
|
||||
|x,y,z| op(x,y,z)));
|
||||
|
@ -740,10 +740,6 @@ fn resolve_local(visitor: &mut RegionResolutionVisitor,
|
||||
visitor, &*field.expr, blk_id);
|
||||
}
|
||||
}
|
||||
ast::ExprVstore(ref subexpr, _) => {
|
||||
visitor.region_maps.record_rvalue_scope(subexpr.id, blk_id);
|
||||
record_rvalue_scope_if_borrow_expr(visitor, &**subexpr, blk_id);
|
||||
}
|
||||
ast::ExprVec(ref subexprs) |
|
||||
ast::ExprTup(ref subexprs) => {
|
||||
for subexpr in subexprs.iter() {
|
||||
|
@ -403,7 +403,7 @@ impl<T> VecPerParamSpace<T> {
|
||||
self.content.slice(start, limit)
|
||||
}
|
||||
|
||||
fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] {
|
||||
pub fn get_mut_slice<'a>(&'a mut self, space: ParamSpace) -> &'a mut [T] {
|
||||
let (start, limit) = self.limits(space);
|
||||
self.content.mut_slice(start, limit)
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
|
||||
match *o {
|
||||
lit(lit_expr) => {
|
||||
let lit_ty = ty::node_id_to_type(bcx.tcx(), lit_expr.id);
|
||||
let (llval, _) = consts::const_expr(ccx, &*lit_expr, true);
|
||||
let (llval, _, _) = consts::const_expr(ccx, &*lit_expr, true);
|
||||
let lit_datum = immediate_rvalue(llval, lit_ty);
|
||||
let lit_datum = unpack_datum!(bcx, lit_datum.to_appropriate_datum(bcx));
|
||||
return single_result(Result::new(bcx, lit_datum.val));
|
||||
@ -289,8 +289,8 @@ fn trans_opt<'a>(mut bcx: &'a Block<'a>, o: &Opt) -> opt_result<'a> {
|
||||
return adt::trans_case(bcx, &**repr, disr_val);
|
||||
}
|
||||
range(ref l1, ref l2) => {
|
||||
let (l1, _) = consts::const_expr(ccx, &**l1, true);
|
||||
let (l2, _) = consts::const_expr(ccx, &**l2, true);
|
||||
let (l1, _, _) = consts::const_expr(ccx, &**l1, true);
|
||||
let (l2, _, _) = consts::const_expr(ccx, &**l2, true);
|
||||
return range_result(Result::new(bcx, l1), Result::new(bcx, l2));
|
||||
}
|
||||
vec_len(n, vec_len_eq, _) => {
|
||||
@ -692,7 +692,7 @@ fn extract_vec_elems<'a>(
|
||||
let vec_datum = match_datum(bcx, val, pat_id);
|
||||
let (base, len) = vec_datum.get_vec_base_and_len(bcx);
|
||||
let vec_ty = node_id_type(bcx, pat_id);
|
||||
let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
|
||||
let vt = tvec::vec_types(bcx, ty::sequence_element_type(bcx.tcx(), ty::type_content(vec_ty)));
|
||||
|
||||
let mut elems = Vec::from_fn(elem_count, |i| {
|
||||
match slice {
|
||||
@ -863,7 +863,7 @@ fn compare_values<'a>(
|
||||
match ty::get(rhs_t).sty {
|
||||
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
|
||||
ty::ty_str => compare_str(cx, lhs, rhs, rhs_t),
|
||||
ty::ty_vec(mt, _) => match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(ty, _) => match ty::get(ty).sty {
|
||||
ty::ty_uint(ast::TyU8) => {
|
||||
// NOTE: cast &[u8] to &str and abuse the str_eq lang item,
|
||||
// which calls memcmp().
|
||||
|
@ -127,8 +127,11 @@ pub enum Repr {
|
||||
|
||||
/// For structs, and struct-like parts of anything fancier.
|
||||
pub struct Struct {
|
||||
// If the struct is DST, then the size and alignment do not take into
|
||||
// account the unsized fields of the struct.
|
||||
pub size: u64,
|
||||
pub align: u64,
|
||||
pub sized: bool,
|
||||
pub packed: bool,
|
||||
pub fields: Vec<ty::t>
|
||||
}
|
||||
@ -265,7 +268,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {
|
||||
mk_struct(cx, ftys.as_slice(), false)
|
||||
}).collect(), dtor);
|
||||
}
|
||||
_ => cx.sess().bug("adt::represent_type called on non-ADT type")
|
||||
_ => cx.sess().bug(format!("adt::represent_type called on non-ADT type: {}",
|
||||
ty_to_string(cx.tcx(), t)).as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
@ -286,6 +290,7 @@ impl Case {
|
||||
fn is_zerolen(&self, cx: &CrateContext) -> bool {
|
||||
mk_struct(cx, self.tys.as_slice(), false).size == 0
|
||||
}
|
||||
|
||||
fn find_ptr(&self) -> Option<PointerField> {
|
||||
use back::abi::{fn_field_code, slice_elt_base, trt_field_box};
|
||||
|
||||
@ -305,8 +310,7 @@ impl Case {
|
||||
|
||||
// Box<T> could either be a thin or fat pointer depending on T
|
||||
ty::ty_uniq(t) => match ty::get(t).sty {
|
||||
// Box<[T]>/Box<str> might be FatPointer in a post DST world
|
||||
ty::ty_vec(_, None) | ty::ty_str => continue,
|
||||
ty::ty_vec(_, None) => return Some(FatPointer(i, slice_elt_base)),
|
||||
|
||||
// Box<Trait> is a pair of pointers: the actual object and a vtable
|
||||
ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)),
|
||||
@ -326,7 +330,6 @@ impl Case {
|
||||
|
||||
// Anything else is not a pointer
|
||||
_ => continue
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,13 +347,28 @@ fn get_cases(tcx: &ty::ctxt, def_id: ast::DefId, substs: &subst::Substs) -> Vec<
|
||||
}
|
||||
|
||||
fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
|
||||
let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
|
||||
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
|
||||
Struct {
|
||||
size: machine::llsize_of_alloc(cx, llty_rec) /*bad*/as u64,
|
||||
align: machine::llalign_of_min(cx, llty_rec) /*bad*/as u64,
|
||||
packed: packed,
|
||||
fields: Vec::from_slice(tys),
|
||||
if tys.iter().all(|&ty| ty::type_is_sized(cx.tcx(), ty)) {
|
||||
let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
|
||||
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
|
||||
Struct {
|
||||
size: machine::llsize_of_alloc(cx, llty_rec),
|
||||
align: machine::llalign_of_min(cx, llty_rec),
|
||||
sized: true,
|
||||
packed: packed,
|
||||
fields: Vec::from_slice(tys),
|
||||
}
|
||||
} else {
|
||||
// Ignore any dynamically sized fields.
|
||||
let lltys = tys.iter().filter(|&ty| ty::type_is_sized(cx.tcx(), *ty))
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
|
||||
let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
|
||||
Struct {
|
||||
size: machine::llsize_of_alloc(cx, llty_rec),
|
||||
align: machine::llalign_of_min(cx, llty_rec),
|
||||
sized: false,
|
||||
packed: packed,
|
||||
fields: Vec::from_slice(tys),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -455,31 +473,38 @@ pub fn ty_of_inttype(ity: IntType) -> ty::t {
|
||||
* unbounded recursion; see also the comments in `trans::type_of`.
|
||||
*/
|
||||
pub fn type_of(cx: &CrateContext, r: &Repr) -> Type {
|
||||
generic_type_of(cx, r, None, false)
|
||||
generic_type_of(cx, r, None, false, false)
|
||||
}
|
||||
pub fn sizing_type_of(cx: &CrateContext, r: &Repr) -> Type {
|
||||
generic_type_of(cx, r, None, true)
|
||||
// Pass dst=true if the type you are passing is a DST. Yes, we could figure
|
||||
// this out, but if you call this on an unsized type without realising it, you
|
||||
// are going to get the wrong type (it will not include the unsized parts of it).
|
||||
pub fn sizing_type_of(cx: &CrateContext, r: &Repr, dst: bool) -> Type {
|
||||
generic_type_of(cx, r, None, true, dst)
|
||||
}
|
||||
pub fn incomplete_type_of(cx: &CrateContext, r: &Repr, name: &str) -> Type {
|
||||
generic_type_of(cx, r, Some(name), false)
|
||||
generic_type_of(cx, r, Some(name), false, false)
|
||||
}
|
||||
pub fn finish_type_of(cx: &CrateContext, r: &Repr, llty: &mut Type) {
|
||||
match *r {
|
||||
CEnum(..) | General(..) | RawNullablePointer { .. } => { }
|
||||
Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } =>
|
||||
llty.set_struct_body(struct_llfields(cx, st, false).as_slice(),
|
||||
llty.set_struct_body(struct_llfields(cx, st, false, false).as_slice(),
|
||||
st.packed)
|
||||
}
|
||||
}
|
||||
|
||||
fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool) -> Type {
|
||||
fn generic_type_of(cx: &CrateContext,
|
||||
r: &Repr,
|
||||
name: Option<&str>,
|
||||
sizing: bool,
|
||||
dst: bool) -> Type {
|
||||
match *r {
|
||||
CEnum(ity, _, _) => ll_inttype(cx, ity),
|
||||
RawNullablePointer { nnty, .. } => type_of::sizing_type_of(cx, nnty),
|
||||
Univariant(ref st, _) | StructWrappedNullablePointer { nonnull: ref st, .. } => {
|
||||
match name {
|
||||
None => {
|
||||
Type::struct_(cx, struct_llfields(cx, st, sizing).as_slice(),
|
||||
Type::struct_(cx, struct_llfields(cx, st, sizing, dst).as_slice(),
|
||||
st.packed)
|
||||
}
|
||||
Some(name) => { assert_eq!(sizing, false); Type::named_struct(cx, name) }
|
||||
@ -531,9 +556,10 @@ fn generic_type_of(cx: &CrateContext, r: &Repr, name: Option<&str>, sizing: bool
|
||||
}
|
||||
}
|
||||
|
||||
fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool) -> Vec<Type> {
|
||||
fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool, dst: bool) -> Vec<Type> {
|
||||
if sizing {
|
||||
st.fields.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
st.fields.iter().filter(|&ty| !dst || ty::type_is_sized(cx.tcx(), *ty))
|
||||
.map(|&ty| type_of::sizing_type_of(cx, ty)).collect()
|
||||
} else {
|
||||
st.fields.iter().map(|&ty| type_of::type_of(cx, ty)).collect()
|
||||
}
|
||||
@ -946,7 +972,7 @@ fn compute_struct_field_offsets(ccx: &CrateContext, st: &Struct) -> Vec<u64> {
|
||||
for &ty in st.fields.iter() {
|
||||
let llty = type_of::sizing_type_of(ccx, ty);
|
||||
if !st.packed {
|
||||
let type_align = machine::llalign_of_min(ccx, llty) as u64;
|
||||
let type_align = type_of::align_of(ccx, ty) as u64;
|
||||
offset = roundup(offset, type_align);
|
||||
}
|
||||
offsets.push(offset);
|
||||
@ -990,7 +1016,7 @@ fn build_const_struct(ccx: &CrateContext, st: &Struct, vals: &[ValueRef])
|
||||
offset += machine::llsize_of_alloc(ccx, val_ty(val)) as u64;
|
||||
}
|
||||
|
||||
assert!(offset <= st.size);
|
||||
assert!(st.sized && offset <= st.size);
|
||||
if offset != st.size {
|
||||
cfields.push(padding(ccx, st.size - offset));
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ use middle::trans::glue;
|
||||
use middle::trans::inline;
|
||||
use middle::trans::intrinsic;
|
||||
use middle::trans::machine;
|
||||
use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_real};
|
||||
use middle::trans::machine::{llsize_of, llsize_of_real};
|
||||
use middle::trans::meth;
|
||||
use middle::trans::monomorphize;
|
||||
use middle::trans::tvec;
|
||||
@ -364,20 +364,19 @@ fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId {
|
||||
// a given type, but with a potentially dynamic size.
|
||||
|
||||
pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
|
||||
ptr_ty: ty::t,
|
||||
llty_ptr: Type,
|
||||
info_ty: ty::t,
|
||||
size: ValueRef,
|
||||
align: ValueRef)
|
||||
-> Result<'a> {
|
||||
let _icx = push_ctxt("malloc_raw_exchange");
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
// Allocate space:
|
||||
let r = callee::trans_lang_call(bcx,
|
||||
require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem),
|
||||
require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem),
|
||||
[size, align],
|
||||
None);
|
||||
|
||||
let llty_ptr = type_of::type_of(ccx, ptr_ty);
|
||||
Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
|
||||
}
|
||||
|
||||
@ -395,7 +394,7 @@ pub fn malloc_raw_dyn_managed<'a>(
|
||||
// Grab the TypeRef type of box_ptr_ty.
|
||||
let box_ptr_ty = ty::mk_box(bcx.tcx(), t);
|
||||
let llty = type_of(ccx, box_ptr_ty);
|
||||
let llalign = C_uint(ccx, llalign_of_min(ccx, llty) as uint);
|
||||
let llalign = C_uint(ccx, type_of::align_of(ccx, box_ptr_ty) as uint);
|
||||
|
||||
// Allocate space:
|
||||
let drop_glue = glue::get_drop_glue(ccx, t);
|
||||
@ -711,14 +710,33 @@ pub fn iter_structural_ty<'r,
|
||||
return cx;
|
||||
}
|
||||
|
||||
let (data_ptr, info) = if ty::type_is_sized(cx.tcx(), t) {
|
||||
(av, None)
|
||||
} else {
|
||||
let data = GEPi(cx, av, [0, abi::slice_elt_base]);
|
||||
let info = GEPi(cx, av, [0, abi::slice_elt_len]);
|
||||
(Load(cx, data), Some(Load(cx, info)))
|
||||
};
|
||||
|
||||
let mut cx = cx;
|
||||
match ty::get(t).sty {
|
||||
ty::ty_struct(..) => {
|
||||
let repr = adt::represent_type(cx.ccx(), t);
|
||||
expr::with_field_tys(cx.tcx(), t, None, |discr, field_tys| {
|
||||
for (i, field_ty) in field_tys.iter().enumerate() {
|
||||
let llfld_a = adt::trans_field_ptr(cx, &*repr, av, discr, i);
|
||||
cx = f(cx, llfld_a, field_ty.mt.ty);
|
||||
let field_ty = field_ty.mt.ty;
|
||||
let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, discr, i);
|
||||
|
||||
let val = if ty::type_is_sized(cx.tcx(), field_ty) {
|
||||
llfld_a
|
||||
} else {
|
||||
let boxed_ty = ty::mk_open(cx.tcx(), field_ty);
|
||||
let scratch = datum::rvalue_scratch_datum(cx, boxed_ty, "__fat_ptr_iter");
|
||||
Store(cx, llfld_a, GEPi(cx, scratch.val, [0, abi::slice_elt_base]));
|
||||
Store(cx, info.unwrap(), GEPi(cx, scratch.val, [0, abi::slice_elt_len]));
|
||||
scratch.val
|
||||
};
|
||||
cx = f(cx, val, field_ty);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -726,19 +744,19 @@ pub fn iter_structural_ty<'r,
|
||||
let repr = adt::represent_type(cx.ccx(), t);
|
||||
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
|
||||
for (i, upvar) in upvars.iter().enumerate() {
|
||||
let llupvar = adt::trans_field_ptr(cx, &*repr, av, 0, i);
|
||||
let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
|
||||
cx = f(cx, llupvar, upvar.ty);
|
||||
}
|
||||
}
|
||||
ty::ty_vec(_, Some(n)) => {
|
||||
let (base, len) = tvec::get_fixed_base_and_len(cx, data_ptr, n);
|
||||
let unit_ty = ty::sequence_element_type(cx.tcx(), t);
|
||||
let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n);
|
||||
cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f);
|
||||
}
|
||||
ty::ty_tup(ref args) => {
|
||||
let repr = adt::represent_type(cx.ccx(), t);
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
let llfld_a = adt::trans_field_ptr(cx, &*repr, av, 0, i);
|
||||
let llfld_a = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
|
||||
cx = f(cx, llfld_a, *arg);
|
||||
}
|
||||
}
|
||||
@ -782,7 +800,7 @@ pub fn iter_structural_ty<'r,
|
||||
let variant_cx =
|
||||
iter_variant(variant_cx,
|
||||
&*repr,
|
||||
av,
|
||||
data_ptr,
|
||||
&**variant,
|
||||
substs,
|
||||
|x,y,z| f(x,y,z));
|
||||
@ -956,14 +974,23 @@ pub fn invoke<'a>(
|
||||
llfn: ValueRef,
|
||||
llargs: Vec<ValueRef> ,
|
||||
fn_ty: ty::t,
|
||||
call_info: Option<NodeInfo>)
|
||||
call_info: Option<NodeInfo>,
|
||||
// FIXME(15064) is_lang_item is a horrible hack, please remove it
|
||||
// at the soonest opportunity.
|
||||
is_lang_item: bool)
|
||||
-> (ValueRef, &'a Block<'a>) {
|
||||
let _icx = push_ctxt("invoke_");
|
||||
if bcx.unreachable.get() {
|
||||
return (C_null(Type::i8(bcx.ccx())), bcx);
|
||||
}
|
||||
|
||||
let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty);
|
||||
// FIXME(15064) Lang item methods may (in the reflect case) not have proper
|
||||
// types, so doing an attribute lookup will fail.
|
||||
let attributes = if is_lang_item {
|
||||
llvm::AttrBuilder::new()
|
||||
} else {
|
||||
get_fn_llvm_attributes(bcx.ccx(), fn_ty)
|
||||
};
|
||||
|
||||
match bcx.opt_node_id {
|
||||
None => {
|
||||
@ -1150,7 +1177,7 @@ pub fn memcpy_ty(bcx: &Block, dst: ValueRef, src: ValueRef, t: ty::t) {
|
||||
if ty::type_is_structural(t) {
|
||||
let llty = type_of::type_of(ccx, t);
|
||||
let llsz = llsize_of(ccx, llty);
|
||||
let llalign = llalign_of_min(ccx, llty);
|
||||
let llalign = type_of::align_of(ccx, t);
|
||||
call_memcpy(bcx, dst, src, llsz, llalign as u32);
|
||||
} else {
|
||||
store_ty(bcx, Load(bcx, src), dst, t);
|
||||
@ -1161,9 +1188,7 @@ pub fn zero_mem(cx: &Block, llptr: ValueRef, t: ty::t) {
|
||||
if cx.unreachable.get() { return; }
|
||||
let _icx = push_ctxt("zero_mem");
|
||||
let bcx = cx;
|
||||
let ccx = cx.ccx();
|
||||
let llty = type_of::type_of(ccx, t);
|
||||
memzero(&B(bcx), llptr, llty);
|
||||
memzero(&B(bcx), llptr, t);
|
||||
}
|
||||
|
||||
// Always use this function instead of storing a zero constant to the memory
|
||||
@ -1171,10 +1196,12 @@ pub fn zero_mem(cx: &Block, llptr: ValueRef, t: ty::t) {
|
||||
// allocation for large data structures, and the generated code will be
|
||||
// awful. (A telltale sign of this is large quantities of
|
||||
// `mov [byte ptr foo],0` in the generated code.)
|
||||
fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
|
||||
fn memzero(b: &Builder, llptr: ValueRef, ty: ty::t) {
|
||||
let _icx = push_ctxt("memzero");
|
||||
let ccx = b.ccx;
|
||||
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
|
||||
let intrinsic_key = match ccx.sess().targ_cfg.arch {
|
||||
X86 | Arm | Mips | Mipsel => "llvm.memset.p0i8.i32",
|
||||
X86_64 => "llvm.memset.p0i8.i64"
|
||||
@ -1183,8 +1210,8 @@ fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
|
||||
let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key);
|
||||
let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to());
|
||||
let llzeroval = C_u8(ccx, 0);
|
||||
let size = machine::llsize_of(ccx, ty);
|
||||
let align = C_i32(ccx, llalign_of_min(ccx, ty) as i32);
|
||||
let size = machine::llsize_of(ccx, llty);
|
||||
let align = C_i32(ccx, type_of::align_of(ccx, ty) as i32);
|
||||
let volatile = C_bool(ccx, false);
|
||||
b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], None);
|
||||
}
|
||||
@ -1215,13 +1242,14 @@ pub fn alloca_no_lifetime(cx: &Block, ty: Type, name: &str) -> ValueRef {
|
||||
Alloca(cx, ty, name)
|
||||
}
|
||||
|
||||
pub fn alloca_zeroed(cx: &Block, ty: Type, name: &str) -> ValueRef {
|
||||
pub fn alloca_zeroed(cx: &Block, ty: ty::t, name: &str) -> ValueRef {
|
||||
let llty = type_of::type_of(cx.ccx(), ty);
|
||||
if cx.unreachable.get() {
|
||||
unsafe {
|
||||
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
|
||||
return llvm::LLVMGetUndef(llty.ptr_to().to_ref());
|
||||
}
|
||||
}
|
||||
let p = alloca_no_lifetime(cx, ty, name);
|
||||
let p = alloca_no_lifetime(cx, llty, name);
|
||||
let b = cx.fcx.ccx.builder();
|
||||
b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
|
||||
memzero(&b, p, ty);
|
||||
@ -1640,7 +1668,8 @@ fn copy_unboxed_closure_args_to_allocas<'a>(
|
||||
for j in range(0, args.len()) {
|
||||
let tuple_element_type = untupled_arg_types[j];
|
||||
let tuple_element_datum =
|
||||
tuple_datum.get_element(tuple_element_type,
|
||||
tuple_datum.get_element(bcx,
|
||||
tuple_element_type,
|
||||
|llval| GEPi(bcx, llval, [0, j]));
|
||||
let tuple_element_datum = tuple_element_datum.to_expr_datum();
|
||||
let tuple_element_datum =
|
||||
@ -2302,9 +2331,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
|
||||
match ty::get(ret_ty).sty {
|
||||
// `~` pointer return values never alias because ownership
|
||||
// is transferred
|
||||
ty::ty_uniq(it) if match ty::get(it).sty {
|
||||
ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false
|
||||
} => {}
|
||||
ty::ty_uniq(it) if !ty::type_is_sized(ccx.tcx(), it) => {}
|
||||
ty::ty_uniq(_) => {
|
||||
attrs.ret(llvm::NoAliasAttribute);
|
||||
}
|
||||
@ -2315,9 +2342,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
|
||||
match ty::get(ret_ty).sty {
|
||||
// These are not really pointers but pairs, (pointer, len)
|
||||
ty::ty_uniq(it) |
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
|
||||
ty::ty_str | ty::ty_vec(..) | ty::ty_trait(..) => true, _ => false
|
||||
} => {}
|
||||
ty::ty_rptr(_, ty::mt { ty: it, .. }) if !ty::type_is_sized(ccx.tcx(), it) => {}
|
||||
ty::ty_uniq(inner) | ty::ty_rptr(_, ty::mt { ty: inner, .. }) => {
|
||||
let llret_sz = llsize_of_real(ccx, type_of::type_of(ccx, inner));
|
||||
attrs.ret(llvm::DereferenceableAttribute(llret_sz));
|
||||
@ -2584,7 +2609,7 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
|
||||
|
||||
// We need the translated value here, because for enums the
|
||||
// LLVM type is not fully determined by the Rust type.
|
||||
let (v, inlineable) = consts::const_expr(ccx, &**expr, is_local);
|
||||
let (v, inlineable, _) = consts::const_expr(ccx, &**expr, is_local);
|
||||
ccx.const_values.borrow_mut().insert(id, v);
|
||||
let mut inlineable = inlineable;
|
||||
|
||||
|
@ -51,6 +51,7 @@ use middle::typeck;
|
||||
use middle::typeck::coherence::make_substs_for_receiver_types;
|
||||
use middle::typeck::MethodCall;
|
||||
use util::ppaux::Repr;
|
||||
use util::ppaux::ty_to_string;
|
||||
|
||||
use std::gc::Gc;
|
||||
use syntax::abi as synabi;
|
||||
@ -853,7 +854,8 @@ pub fn trans_call_inner<'a>(
|
||||
llfn,
|
||||
llargs,
|
||||
callee_ty,
|
||||
call_info);
|
||||
call_info,
|
||||
dest.is_none());
|
||||
bcx = b;
|
||||
llresult = llret;
|
||||
|
||||
@ -968,6 +970,7 @@ fn trans_args_under_call_abi<'a>(
|
||||
let repr_ptr = &*repr;
|
||||
for i in range(0, field_types.len()) {
|
||||
let arg_datum = tuple_lvalue_datum.get_element(
|
||||
bcx,
|
||||
*field_types.get(i),
|
||||
|srcval| {
|
||||
adt::trans_field_ptr(bcx, repr_ptr, srcval, 0, i)
|
||||
@ -1194,6 +1197,8 @@ pub fn trans_arg_datum<'a>(
|
||||
let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
|
||||
debug!("casting actual type ({}) to match formal ({})",
|
||||
bcx.val_to_string(val), bcx.llty_str(llformal_arg_ty));
|
||||
debug!("Rust types: {}; {}", ty_to_string(bcx.tcx(), arg_datum_ty),
|
||||
ty_to_string(bcx.tcx(), formal_arg_ty));
|
||||
val = PointerCast(bcx, val, llformal_arg_ty);
|
||||
}
|
||||
}
|
||||
|
@ -65,14 +65,18 @@ fn type_is_newtype_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
|
||||
pub fn type_is_immediate(ccx: &CrateContext, ty: ty::t) -> bool {
|
||||
use middle::trans::machine::llsize_of_alloc;
|
||||
use middle::trans::type_of::sizing_type_of;
|
||||
|
||||
let tcx = ccx.tcx();
|
||||
let simple = ty::type_is_scalar(ty) || ty::type_is_boxed(ty) ||
|
||||
ty::type_is_unique(ty) || ty::type_is_region_ptr(ty) ||
|
||||
type_is_newtype_immediate(ccx, ty) || ty::type_is_bot(ty) ||
|
||||
ty::type_is_simd(tcx, ty);
|
||||
if simple && !ty::type_is_trait(ty) {
|
||||
if simple && !ty::type_is_fat_ptr(tcx, ty) {
|
||||
return true;
|
||||
}
|
||||
if !ty::type_is_sized(tcx, ty) {
|
||||
return false;
|
||||
}
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_bot => true,
|
||||
ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) |
|
||||
|
@ -11,11 +11,9 @@
|
||||
|
||||
use back::abi;
|
||||
use llvm;
|
||||
use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True,
|
||||
False};
|
||||
use llvm::{ConstFCmp, ConstICmp, SetLinkage, PrivateLinkage, ValueRef, Bool, True, False};
|
||||
use llvm::{IntEQ, IntNE, IntUGT, IntUGE, IntULT, IntULE, IntSGT, IntSGE, IntSLT, IntSLE,
|
||||
RealOEQ, RealOGT, RealOGE, RealOLT, RealOLE, RealONE};
|
||||
|
||||
use metadata::csearch;
|
||||
use middle::const_eval;
|
||||
use middle::def;
|
||||
@ -98,12 +96,17 @@ pub fn const_ptrcast(cx: &CrateContext, a: ValueRef, t: Type) -> ValueRef {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function because we don't have tuple-swizzling.
|
||||
fn first_two<R, S, T>((a, b, _): (R, S, T)) -> (R, S) {
|
||||
(a, b)
|
||||
}
|
||||
|
||||
fn const_vec(cx: &CrateContext, e: &ast::Expr,
|
||||
es: &[Gc<ast::Expr>], is_local: bool) -> (ValueRef, Type, bool) {
|
||||
let vec_ty = ty::expr_ty(cx.tcx(), e);
|
||||
let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty);
|
||||
let llunitty = type_of::type_of(cx, unit_ty);
|
||||
let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, &**e, is_local)));
|
||||
let (vs, inlineable) = vec::unzip(es.iter().map(|e| first_two(const_expr(cx, &**e, is_local))));
|
||||
// If the vector contains enums, an LLVM array won't work.
|
||||
let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) {
|
||||
C_struct(cx, vs.as_slice(), false)
|
||||
@ -113,13 +116,14 @@ fn const_vec(cx: &CrateContext, e: &ast::Expr,
|
||||
(v, llunitty, inlineable.iter().fold(true, |a, &b| a && b))
|
||||
}
|
||||
|
||||
pub fn const_addr_of(cx: &CrateContext, cv: ValueRef) -> ValueRef {
|
||||
pub fn const_addr_of(cx: &CrateContext, cv: ValueRef, mutbl: ast::Mutability) -> ValueRef {
|
||||
unsafe {
|
||||
let gv = "const".with_c_str(|name| {
|
||||
llvm::LLVMAddGlobal(cx.llmod, val_ty(cv).to_ref(), name)
|
||||
});
|
||||
llvm::LLVMSetInitializer(gv, cv);
|
||||
llvm::LLVMSetGlobalConstant(gv, True);
|
||||
llvm::LLVMSetGlobalConstant(gv,
|
||||
if mutbl == ast::MutImmutable {True} else {False});
|
||||
SetLinkage(gv, PrivateLinkage);
|
||||
gv
|
||||
}
|
||||
@ -131,7 +135,6 @@ fn const_deref_ptr(cx: &CrateContext, v: ValueRef) -> ValueRef {
|
||||
None => v
|
||||
};
|
||||
unsafe {
|
||||
assert_eq!(llvm::LLVMIsGlobalConstant(v), True);
|
||||
llvm::LLVMGetInitializer(v)
|
||||
}
|
||||
}
|
||||
@ -146,25 +149,25 @@ fn const_deref(cx: &CrateContext, v: ValueRef, t: ty::t, explicit: bool)
|
||||
-> (ValueRef, ty::t) {
|
||||
match ty::deref(t, explicit) {
|
||||
Some(ref mt) => {
|
||||
assert!(mt.mutbl != ast::MutMutable);
|
||||
let dv = match ty::get(t).sty {
|
||||
match ty::get(t).sty {
|
||||
ty::ty_ptr(mt) | ty::ty_rptr(_, mt) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {
|
||||
cx.sess().bug("unexpected unsized type")
|
||||
}
|
||||
_ => const_deref_ptr(cx, v),
|
||||
if ty::type_is_sized(cx.tcx(), mt.ty) {
|
||||
(const_deref_ptr(cx, v), mt.ty)
|
||||
} else {
|
||||
// Derefing a fat pointer does not change the representation,
|
||||
// just the type to ty_open.
|
||||
(v, ty::mk_open(cx.tcx(), mt.ty))
|
||||
}
|
||||
}
|
||||
ty::ty_enum(..) | ty::ty_struct(..) => {
|
||||
const_deref_newtype(cx, v, t)
|
||||
assert!(mt.mutbl != ast::MutMutable);
|
||||
(const_deref_newtype(cx, v, t), mt.ty)
|
||||
}
|
||||
_ => {
|
||||
cx.sess().bug(format!("unexpected dereferenceable type {}",
|
||||
ty_to_string(cx.tcx(), t)).as_slice())
|
||||
}
|
||||
};
|
||||
(dv, mt.ty)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
cx.sess().bug(format!("can't dereference const of type {}",
|
||||
@ -193,12 +196,12 @@ pub fn get_const_val(cx: &CrateContext,
|
||||
!cx.non_inlineable_statics.borrow().contains(&def_id.node))
|
||||
}
|
||||
|
||||
pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool) {
|
||||
pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef, bool, ty::t) {
|
||||
let (llconst, inlineable) = const_expr_unadjusted(cx, e, is_local);
|
||||
let mut llconst = llconst;
|
||||
let mut inlineable = inlineable;
|
||||
let ety = ty::expr_ty(cx.tcx(), e);
|
||||
let ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e);
|
||||
let mut ety_adjusted = ty::expr_ty_adjusted(cx.tcx(), e);
|
||||
let opt_adj = cx.tcx.adjustments.borrow().find_copy(&e.id);
|
||||
match opt_adj {
|
||||
None => { }
|
||||
@ -219,51 +222,64 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef
|
||||
format!("unexpected static function: {:?}",
|
||||
store).as_slice())
|
||||
}
|
||||
ty::AutoObject(..) => {
|
||||
cx.sess()
|
||||
.span_unimpl(e.span,
|
||||
"unimplemented const coercion to trait \
|
||||
object");
|
||||
}
|
||||
ty::AutoDerefRef(ref adj) => {
|
||||
let mut ty = ety;
|
||||
let mut maybe_ptr = None;
|
||||
for _ in range(0, adj.autoderefs) {
|
||||
// Save the last autoderef in case we can avoid it.
|
||||
for _ in range(0, adj.autoderefs-1) {
|
||||
let (dv, dt) = const_deref(cx, llconst, ty, false);
|
||||
maybe_ptr = Some(llconst);
|
||||
llconst = dv;
|
||||
ty = dt;
|
||||
}
|
||||
|
||||
match adj.autoref {
|
||||
None => { }
|
||||
None => {
|
||||
let (dv, dt) = const_deref(cx, llconst, ty, false);
|
||||
llconst = dv;
|
||||
|
||||
// If we derefed a fat pointer then we will have an
|
||||
// open type here. So we need to update the type with
|
||||
// the one returned from const_deref.
|
||||
ety_adjusted = dt;
|
||||
}
|
||||
Some(ref autoref) => {
|
||||
// Don't copy data to do a deref+ref.
|
||||
let llptr = match maybe_ptr {
|
||||
Some(ptr) => ptr,
|
||||
None => {
|
||||
inlineable = false;
|
||||
const_addr_of(cx, llconst)
|
||||
}
|
||||
};
|
||||
match *autoref {
|
||||
ty::AutoUnsafe(m) |
|
||||
ty::AutoPtr(ty::ReStatic, m) => {
|
||||
assert!(m != ast::MutMutable);
|
||||
llconst = llptr;
|
||||
ty::AutoUnsafe(_) |
|
||||
ty::AutoPtr(ty::ReStatic, _, None) => {
|
||||
// Don't copy data to do a deref+ref
|
||||
// (i.e., skip the last auto-deref).
|
||||
if adj.autoderefs == 0 {
|
||||
inlineable = false;
|
||||
llconst = const_addr_of(cx, llconst, ast::MutImmutable);
|
||||
}
|
||||
}
|
||||
ty::AutoBorrowVec(ty::ReStatic, m) => {
|
||||
assert!(m != ast::MutMutable);
|
||||
assert_eq!(abi::slice_elt_base, 0);
|
||||
assert_eq!(abi::slice_elt_len, 1);
|
||||
ty::AutoPtr(ty::ReStatic, _, Some(box ty::AutoUnsize(..))) => {
|
||||
if adj.autoderefs > 0 {
|
||||
// Seeing as we are deref'ing here and take a reference
|
||||
// again to make the pointer part of the far pointer below,
|
||||
// we just skip the whole thing. We still need the type
|
||||
// though. This works even if we don't need to deref
|
||||
// because of byref semantics. Note that this is not just
|
||||
// an optimisation, it is necessary for mutable vectors to
|
||||
// work properly.
|
||||
let (_, dt) = const_deref(cx, llconst, ty, false);
|
||||
ty = dt;
|
||||
}
|
||||
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_vec(_, Some(len)) => {
|
||||
ty::ty_vec(unit_ty, Some(len)) => {
|
||||
inlineable = false;
|
||||
let llunitty = type_of::type_of(cx, unit_ty);
|
||||
let llptr = const_ptrcast(cx, llconst, llunitty);
|
||||
assert_eq!(abi::slice_elt_base, 0);
|
||||
assert_eq!(abi::slice_elt_len, 1);
|
||||
llconst = C_struct(cx, [
|
||||
llptr,
|
||||
C_uint(cx, len)
|
||||
], false);
|
||||
}
|
||||
_ => {}
|
||||
_ => cx.sess().span_bug(e.span,
|
||||
format!("unimplemented type in const unsize: {}",
|
||||
ty_to_string(cx.tcx(), ty)).as_slice())
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@ -294,7 +310,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef
|
||||
e.repr(cx.tcx()), ty_to_string(cx.tcx(), ety),
|
||||
csize, tsize).as_slice());
|
||||
}
|
||||
(llconst, inlineable)
|
||||
(llconst, inlineable, ety_adjusted)
|
||||
}
|
||||
|
||||
// the bool returned is whether this expression can be inlined into other crates
|
||||
@ -302,7 +318,7 @@ pub fn const_expr(cx: &CrateContext, e: &ast::Expr, is_local: bool) -> (ValueRef
|
||||
fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
is_local: bool) -> (ValueRef, bool) {
|
||||
let map_list = |exprs: &[Gc<ast::Expr>]| {
|
||||
exprs.iter().map(|e| const_expr(cx, &**e, is_local))
|
||||
exprs.iter().map(|e| first_two(const_expr(cx, &**e, is_local)))
|
||||
.fold((Vec::new(), true),
|
||||
|(l, all_inlineable), (val, inlineable)| {
|
||||
(l.append_one(val), all_inlineable && inlineable)
|
||||
@ -315,8 +331,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
(consts::const_lit(cx, e, (**lit).clone()), true)
|
||||
}
|
||||
ast::ExprBinary(b, ref e1, ref e2) => {
|
||||
let (te1, _) = const_expr(cx, &**e1, is_local);
|
||||
let (te2, _) = const_expr(cx, &**e2, is_local);
|
||||
let (te1, _, _) = const_expr(cx, &**e1, is_local);
|
||||
let (te2, _, _) = const_expr(cx, &**e2, is_local);
|
||||
|
||||
let te2 = base::cast_shift_const_rhs(b, te1, te2);
|
||||
|
||||
@ -397,7 +413,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
}, true)
|
||||
},
|
||||
ast::ExprUnary(u, ref e) => {
|
||||
let (te, _) = const_expr(cx, &**e, is_local);
|
||||
let (te, _, _) = const_expr(cx, &**e, is_local);
|
||||
let ty = ty::expr_ty(cx.tcx(), &**e);
|
||||
let is_float = ty::type_is_fp(ty);
|
||||
return (match u {
|
||||
@ -413,9 +429,8 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
}, true)
|
||||
}
|
||||
ast::ExprField(ref base, field, _) => {
|
||||
let bt = ty::expr_ty_adjusted(cx.tcx(), &**base);
|
||||
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
|
||||
let brepr = adt::represent_type(cx, bt);
|
||||
let (bv, inlineable) = const_expr(cx, &**base, is_local);
|
||||
expr::with_field_tys(cx.tcx(), bt, None, |discr, field_tys| {
|
||||
let ix = ty::field_idx_strict(cx.tcx(), field.node.name, field_tys);
|
||||
(adt::const_get_field(cx, &*brepr, bv, discr, ix), inlineable)
|
||||
@ -423,8 +438,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
}
|
||||
|
||||
ast::ExprIndex(ref base, ref index) => {
|
||||
let bt = ty::expr_ty_adjusted(cx.tcx(), &**base);
|
||||
let (bv, inlineable) = const_expr(cx, &**base, is_local);
|
||||
let (bv, inlineable, bt) = const_expr(cx, &**base, is_local);
|
||||
let iv = match const_eval::eval_const_expr(cx.tcx(), &**index) {
|
||||
const_eval::const_int(i) => i as u64,
|
||||
const_eval::const_uint(u) => u,
|
||||
@ -433,16 +447,29 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
};
|
||||
let (arr, len) = match ty::get(bt).sty {
|
||||
ty::ty_vec(_, Some(u)) => (bv, C_uint(cx, u)),
|
||||
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
|
||||
ty::ty_open(ty) => match ty::get(ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => {
|
||||
let e1 = const_get_elt(cx, bv, [0]);
|
||||
(const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1]))
|
||||
},
|
||||
_ => cx.sess().span_bug(base.span,
|
||||
"index-expr base must be a vector or string type")
|
||||
format!("index-expr base must be a vector \
|
||||
or string type, found {}",
|
||||
ty_to_string(cx.tcx(), bt)).as_slice())
|
||||
},
|
||||
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(_, Some(u)) => {
|
||||
(const_deref_ptr(cx, bv), C_uint(cx, u))
|
||||
},
|
||||
_ => cx.sess().span_bug(base.span,
|
||||
format!("index-expr base must be a vector \
|
||||
or string type, found {}",
|
||||
ty_to_string(cx.tcx(), bt)).as_slice())
|
||||
},
|
||||
_ => cx.sess().span_bug(base.span,
|
||||
"index-expr base must be a vector or string type")
|
||||
format!("index-expr base must be a vector \
|
||||
or string type, found {}",
|
||||
ty_to_string(cx.tcx(), bt)).as_slice())
|
||||
};
|
||||
|
||||
let len = llvm::LLVMConstIntGetZExtValue(len) as u64;
|
||||
@ -467,10 +494,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
ast::ExprCast(ref base, _) => {
|
||||
let ety = ty::expr_ty(cx.tcx(), e);
|
||||
let llty = type_of::type_of(cx, ety);
|
||||
let basety = ty::expr_ty(cx.tcx(), &**base);
|
||||
let (v, inlineable) = const_expr(cx, &**base, is_local);
|
||||
return (match (expr::cast_type_kind(basety),
|
||||
expr::cast_type_kind(ety)) {
|
||||
let (v, inlineable, basety) = const_expr(cx, &**base, is_local);
|
||||
return (match (expr::cast_type_kind(cx.tcx(), basety),
|
||||
expr::cast_type_kind(cx.tcx(), ety)) {
|
||||
|
||||
(expr::cast_integral, expr::cast_integral) => {
|
||||
let s = ty::type_is_signed(basety) as Bool;
|
||||
@ -494,7 +520,7 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
let repr = adt::represent_type(cx, basety);
|
||||
let discr = adt::const_get_discrim(cx, &*repr, v);
|
||||
let iv = C_integral(cx.int_type, discr, false);
|
||||
let ety_cast = expr::cast_type_kind(ety);
|
||||
let ety_cast = expr::cast_type_kind(cx.tcx(), ety);
|
||||
match ety_cast {
|
||||
expr::cast_integral => {
|
||||
let s = ty::type_is_signed(ety) as Bool;
|
||||
@ -516,9 +542,9 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
}
|
||||
}, inlineable)
|
||||
}
|
||||
ast::ExprAddrOf(ast::MutImmutable, ref sub) => {
|
||||
let (e, _) = const_expr(cx, &**sub, is_local);
|
||||
(const_addr_of(cx, e), false)
|
||||
ast::ExprAddrOf(mutbl, ref sub) => {
|
||||
let (e, _, _) = const_expr(cx, &**sub, is_local);
|
||||
(const_addr_of(cx, e, mutbl), false)
|
||||
}
|
||||
ast::ExprTup(ref es) => {
|
||||
let ety = ty::expr_ty(cx.tcx(), e);
|
||||
@ -540,10 +566,10 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
let (cs, inlineable) = vec::unzip(field_tys.iter().enumerate()
|
||||
.map(|(ix, &field_ty)| {
|
||||
match fs.iter().find(|f| field_ty.ident.name == f.ident.node.name) {
|
||||
Some(ref f) => const_expr(cx, &*f.expr, is_local),
|
||||
Some(ref f) => first_two(const_expr(cx, &*f.expr, is_local)),
|
||||
None => {
|
||||
match base_val {
|
||||
Some((bv, inlineable)) => {
|
||||
Some((bv, inlineable, _)) => {
|
||||
(adt::const_get_field(cx, &*repr, bv, discr, ix),
|
||||
inlineable)
|
||||
}
|
||||
@ -563,34 +589,6 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
is_local);
|
||||
(v, inlineable)
|
||||
}
|
||||
ast::ExprVstore(ref sub, store @ ast::ExprVstoreSlice) |
|
||||
ast::ExprVstore(ref sub, store @ ast::ExprVstoreMutSlice) => {
|
||||
match sub.node {
|
||||
ast::ExprLit(ref lit) => {
|
||||
match lit.node {
|
||||
ast::LitStr(..) => { const_expr(cx, &**sub, is_local) }
|
||||
_ => { cx.sess().span_bug(e.span, "bad const-slice lit") }
|
||||
}
|
||||
}
|
||||
ast::ExprVec(ref es) => {
|
||||
let (cv, llunitty, _) = const_vec(cx,
|
||||
e,
|
||||
es.as_slice(),
|
||||
is_local);
|
||||
let llty = val_ty(cv);
|
||||
let gv = "const".with_c_str(|name| {
|
||||
llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name)
|
||||
});
|
||||
llvm::LLVMSetInitializer(gv, cv);
|
||||
llvm::LLVMSetGlobalConstant(gv,
|
||||
if store == ast::ExprVstoreMutSlice { False } else { True });
|
||||
SetLinkage(gv, PrivateLinkage);
|
||||
let p = const_ptrcast(cx, gv, llunitty);
|
||||
(C_struct(cx, [p, C_uint(cx, es.len())], false), false)
|
||||
}
|
||||
_ => cx.sess().span_bug(e.span, "bad const-slice expr")
|
||||
}
|
||||
}
|
||||
ast::ExprRepeat(ref elem, ref count) => {
|
||||
let vec_ty = ty::expr_ty(cx.tcx(), e);
|
||||
let unit_ty = ty::sequence_element_type(cx.tcx(), vec_ty);
|
||||
@ -669,10 +667,10 @@ fn const_expr_unadjusted(cx: &CrateContext, e: &ast::Expr,
|
||||
_ => cx.sess().span_bug(e.span, "expected a struct or variant def")
|
||||
}
|
||||
}
|
||||
ast::ExprParen(ref e) => { const_expr(cx, &**e, is_local) }
|
||||
ast::ExprParen(ref e) => first_two(const_expr(cx, &**e, is_local)),
|
||||
ast::ExprBlock(ref block) => {
|
||||
match block.expr {
|
||||
Some(ref expr) => const_expr(cx, &**expr, is_local),
|
||||
Some(ref expr) => first_two(const_expr(cx, &**expr, is_local)),
|
||||
None => (C_nil(cx), true)
|
||||
}
|
||||
}
|
||||
|
@ -497,7 +497,7 @@ pub fn trans_fail<'a>(
|
||||
let filename = C_str_slice(ccx, filename);
|
||||
let line = C_int(ccx, loc.line as int);
|
||||
let expr_file_line_const = C_struct(ccx, &[v_str, filename, line], false);
|
||||
let expr_file_line = consts::const_addr_of(ccx, expr_file_line_const);
|
||||
let expr_file_line = consts::const_addr_of(ccx, expr_file_line_const, ast::MutImmutable);
|
||||
let args = vec!(expr_file_line);
|
||||
let did = langcall(bcx, Some(sp), "", FailFnLangItem);
|
||||
let bcx = callee::trans_lang_call(bcx,
|
||||
@ -525,7 +525,7 @@ pub fn trans_fail_bounds_check<'a>(
|
||||
let filename = C_str_slice(ccx, filename);
|
||||
let line = C_int(ccx, loc.line as int);
|
||||
let file_line_const = C_struct(ccx, &[filename, line], false);
|
||||
let file_line = consts::const_addr_of(ccx, file_line_const);
|
||||
let file_line = consts::const_addr_of(ccx, file_line_const, ast::MutImmutable);
|
||||
let args = vec!(file_line, index, len);
|
||||
let did = langcall(bcx, Some(sp), "", FailBoundsCheckFnLangItem);
|
||||
let bcx = callee::trans_lang_call(bcx,
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
use llvm::ValueRef;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::Load;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::cleanup;
|
||||
use middle::trans::cleanup::CleanupMethods;
|
||||
@ -119,10 +120,10 @@ pub fn lvalue_scratch_datum<'a, A>(bcx: &'a Block<'a>,
|
||||
* does not dominate the end of `scope`.
|
||||
*/
|
||||
|
||||
let llty = type_of::type_of(bcx.ccx(), ty);
|
||||
let scratch = if zero {
|
||||
alloca_zeroed(bcx, llty, name)
|
||||
alloca_zeroed(bcx, ty, name)
|
||||
} else {
|
||||
let llty = type_of::type_of(bcx.ccx(), ty);
|
||||
alloca(bcx, llty, name)
|
||||
};
|
||||
|
||||
@ -450,6 +451,8 @@ impl Datum<Expr> {
|
||||
name: &str,
|
||||
expr_id: ast::NodeId)
|
||||
-> DatumBlock<'a, Lvalue> {
|
||||
assert!(ty::lltype_is_sized(bcx.tcx(), self.ty),
|
||||
"Trying to convert unsized value to lval");
|
||||
self.match_kind(
|
||||
|l| DatumBlock::new(bcx, l),
|
||||
|r| {
|
||||
@ -504,12 +507,28 @@ impl Datum<Lvalue> {
|
||||
self.val
|
||||
}
|
||||
|
||||
pub fn get_element(&self,
|
||||
ty: ty::t,
|
||||
gep: |ValueRef| -> ValueRef)
|
||||
-> Datum<Lvalue> {
|
||||
// Extracts a component of a compound data structure (e.g., a field from a
|
||||
// struct). Note that if self is an opened, unsized type then the returned
|
||||
// datum may also be unsized _without the size information_. It is the
|
||||
// callers responsibility to package the result in some way to make a valid
|
||||
// datum in that case (e.g., by making a fat pointer or opened pair).
|
||||
pub fn get_element<'a>(&self,
|
||||
bcx: &'a Block<'a>,
|
||||
ty: ty::t,
|
||||
gep: |ValueRef| -> ValueRef)
|
||||
-> Datum<Lvalue> {
|
||||
let val = match ty::get(self.ty).sty {
|
||||
_ if ty::type_is_sized(bcx.tcx(), self.ty) => gep(self.val),
|
||||
ty::ty_open(_) => {
|
||||
let base = Load(bcx, expr::get_dataptr(bcx, self.val));
|
||||
gep(base)
|
||||
}
|
||||
_ => bcx.tcx().sess.bug(
|
||||
format!("Unexpected unsized type in get_element: {}",
|
||||
bcx.ty_to_string(self.ty)).as_slice())
|
||||
};
|
||||
Datum {
|
||||
val: gep(self.val),
|
||||
val: val,
|
||||
kind: Lvalue,
|
||||
ty: ty,
|
||||
}
|
||||
|
@ -56,10 +56,11 @@ This file consists of three conceptual sections:
|
||||
## Recursive Types
|
||||
|
||||
Some kinds of types, such as structs and enums can be recursive. That means that
|
||||
the type definition of some type X refers to some other type which in turn (transitively)
|
||||
refers to X. This introduces cycles into the type referral graph. A naive algorithm doing
|
||||
an on-demand, depth-first traversal of this graph when describing types, can get trapped
|
||||
in an endless loop when it reaches such a cycle.
|
||||
the type definition of some type X refers to some other type which in turn
|
||||
(transitively) refers to X. This introduces cycles into the type referral graph.
|
||||
A naive algorithm doing an on-demand, depth-first traversal of this graph when
|
||||
describing types, can get trapped in an endless loop when it reaches such a
|
||||
cycle.
|
||||
|
||||
For example, the following simple type for a singly-linked list...
|
||||
|
||||
@ -402,7 +403,7 @@ impl TypeMap {
|
||||
let inner_type_id = self.get_unique_type_id_as_string(inner_type_id);
|
||||
unique_type_id.push_str(inner_type_id.as_slice());
|
||||
},
|
||||
ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => {
|
||||
ty::ty_vec(inner_type, optional_length) => {
|
||||
match optional_length {
|
||||
Some(len) => {
|
||||
unique_type_id.push_str(format!("[{}]", len).as_slice());
|
||||
@ -595,18 +596,6 @@ impl TypeMap {
|
||||
UniqueTypeId(interner_key)
|
||||
}
|
||||
|
||||
fn get_unique_type_id_of_heap_vec_box(&mut self,
|
||||
cx: &CrateContext,
|
||||
element_type: ty::t)
|
||||
-> UniqueTypeId {
|
||||
let element_type_id = self.get_unique_type_id_of_type(cx, element_type);
|
||||
let heap_vec_box_type_id = format!("{{HEAP_VEC_BOX<{}>}}",
|
||||
self.get_unique_type_id_as_string(element_type_id)
|
||||
.as_slice());
|
||||
let interner_key = self.unique_id_interner.intern(Rc::new(heap_vec_box_type_id));
|
||||
UniqueTypeId(interner_key)
|
||||
}
|
||||
|
||||
fn get_unique_type_id_of_gc_box(&mut self,
|
||||
cx: &CrateContext,
|
||||
element_type: ty::t)
|
||||
@ -2718,81 +2707,6 @@ fn fixed_vec_metadata(cx: &CrateContext,
|
||||
return MetadataCreationResult::new(metadata, false);
|
||||
}
|
||||
|
||||
fn heap_vec_metadata(cx: &CrateContext,
|
||||
vec_pointer_type: ty::t,
|
||||
element_type: ty::t,
|
||||
unique_type_id: UniqueTypeId,
|
||||
span: Span)
|
||||
-> MetadataCreationResult {
|
||||
let element_type_metadata = type_metadata(cx, element_type, span);
|
||||
let element_llvm_type = type_of::type_of(cx, element_type);
|
||||
let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
|
||||
|
||||
return_if_metadata_created_in_meantime!(cx, unique_type_id);
|
||||
|
||||
let vecbox_llvm_type = Type::vec(cx, &element_llvm_type);
|
||||
let vec_pointer_type_name = compute_debuginfo_type_name(cx,
|
||||
vec_pointer_type,
|
||||
true);
|
||||
let vec_pointer_type_name = vec_pointer_type_name.as_slice();
|
||||
|
||||
let member_llvm_types = vecbox_llvm_type.field_types();
|
||||
|
||||
let int_type_metadata = type_metadata(cx, ty::mk_int(), span);
|
||||
let array_type_metadata = unsafe {
|
||||
llvm::LLVMDIBuilderCreateArrayType(
|
||||
DIB(cx),
|
||||
bytes_to_bits(element_size),
|
||||
bytes_to_bits(element_align),
|
||||
element_type_metadata,
|
||||
create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)]))
|
||||
};
|
||||
|
||||
let member_descriptions = [
|
||||
MemberDescription {
|
||||
name: "fill".to_string(),
|
||||
llvm_type: *member_llvm_types.get(0),
|
||||
type_metadata: int_type_metadata,
|
||||
offset: ComputedMemberOffset,
|
||||
},
|
||||
MemberDescription {
|
||||
name: "alloc".to_string(),
|
||||
llvm_type: *member_llvm_types.get(1),
|
||||
type_metadata: int_type_metadata,
|
||||
offset: ComputedMemberOffset,
|
||||
},
|
||||
MemberDescription {
|
||||
name: "elements".to_string(),
|
||||
llvm_type: *member_llvm_types.get(2),
|
||||
type_metadata: array_type_metadata,
|
||||
offset: ComputedMemberOffset,
|
||||
}
|
||||
];
|
||||
|
||||
assert!(member_descriptions.len() == member_llvm_types.len());
|
||||
|
||||
let loc = span_start(cx, span);
|
||||
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
|
||||
|
||||
let vec_box_unique_id = debug_context(cx).type_map
|
||||
.borrow_mut()
|
||||
.get_unique_type_id_of_heap_vec_box(cx,
|
||||
element_type);
|
||||
|
||||
let vecbox_metadata = composite_type_metadata(cx,
|
||||
vecbox_llvm_type,
|
||||
vec_pointer_type_name,
|
||||
vec_box_unique_id,
|
||||
member_descriptions,
|
||||
UNKNOWN_SCOPE_METADATA,
|
||||
file_metadata,
|
||||
span);
|
||||
|
||||
MetadataCreationResult::new(pointer_type_metadata(cx,
|
||||
vec_pointer_type,
|
||||
vecbox_metadata), false)
|
||||
}
|
||||
|
||||
fn vec_slice_metadata(cx: &CrateContext,
|
||||
vec_type: ty::t,
|
||||
element_type: ty::t,
|
||||
@ -2885,47 +2799,42 @@ fn subroutine_type_metadata(cx: &CrateContext,
|
||||
false);
|
||||
}
|
||||
|
||||
// FIXME(1563) This is all a bit of a hack because 'trait pointer' is an ill-
|
||||
// defined concept. For the case of an actual trait pointer (i.e., Box<Trait>,
|
||||
// &Trait), trait_object_type should be the whole thing (e.g, Box<Trait>) and
|
||||
// trait_type should be the actual trait (e.g., Trait). Where the trait is part
|
||||
// of a DST struct, there is no trait_object_type and the results of this
|
||||
// function will be a little bit weird.
|
||||
fn trait_pointer_metadata(cx: &CrateContext,
|
||||
// trait_pointer_type must be the type of the fat
|
||||
// pointer to the concrete trait object
|
||||
trait_pointer_type: ty::t,
|
||||
trait_type: ty::t,
|
||||
trait_object_type: Option<ty::t>,
|
||||
unique_type_id: UniqueTypeId)
|
||||
-> DIType {
|
||||
// The implementation provided here is a stub. It makes sure that the trait
|
||||
// type is assigned the correct name, size, namespace, and source location.
|
||||
// But it does not describe the trait's methods.
|
||||
|
||||
let trait_object_type = match ty::get(trait_pointer_type).sty {
|
||||
ty::ty_uniq(pointee_type) => pointee_type,
|
||||
ty::ty_rptr(_, ty::mt { ty, .. }) => ty,
|
||||
_ => {
|
||||
let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_pointer_type);
|
||||
cx.sess().bug(format!("debuginfo: Unexpected trait-pointer type in \
|
||||
trait_pointer_metadata(): {}",
|
||||
pp_type_name.as_slice()).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
let def_id = match ty::get(trait_object_type).sty {
|
||||
let def_id = match ty::get(trait_type).sty {
|
||||
ty::ty_trait(box ty::TyTrait { def_id, .. }) => def_id,
|
||||
_ => {
|
||||
let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_object_type);
|
||||
let pp_type_name = ppaux::ty_to_string(cx.tcx(), trait_type);
|
||||
cx.sess().bug(format!("debuginfo: Unexpected trait-object type in \
|
||||
trait_pointer_metadata(): {}",
|
||||
pp_type_name.as_slice()).as_slice());
|
||||
}
|
||||
};
|
||||
|
||||
let trait_pointer_type_name =
|
||||
compute_debuginfo_type_name(cx, trait_pointer_type, false);
|
||||
let trait_object_type = trait_object_type.unwrap_or(trait_type);
|
||||
let trait_type_name =
|
||||
compute_debuginfo_type_name(cx, trait_object_type, false);
|
||||
|
||||
let (containing_scope, _) = get_namespace_and_span_for_item(cx, def_id);
|
||||
|
||||
let trait_pointer_llvm_type = type_of::type_of(cx, trait_pointer_type);
|
||||
let trait_llvm_type = type_of::type_of(cx, trait_object_type);
|
||||
|
||||
composite_type_metadata(cx,
|
||||
trait_pointer_llvm_type,
|
||||
trait_pointer_type_name.as_slice(),
|
||||
trait_llvm_type,
|
||||
trait_type_name.as_slice(),
|
||||
unique_type_id,
|
||||
[],
|
||||
containing_scope,
|
||||
@ -2989,27 +2898,33 @@ fn type_metadata(cx: &CrateContext,
|
||||
ty::ty_box(pointee_type) => {
|
||||
at_box_metadata(cx, t, pointee_type, unique_type_id)
|
||||
}
|
||||
ty::ty_vec(ref mt, Some(len)) => {
|
||||
fixed_vec_metadata(cx, unique_type_id, mt.ty, len, usage_site_span)
|
||||
ty::ty_vec(typ, Some(len)) => {
|
||||
fixed_vec_metadata(cx, unique_type_id, typ, len, usage_site_span)
|
||||
}
|
||||
ty::ty_uniq(pointee_type) => {
|
||||
match ty::get(pointee_type).sty {
|
||||
ty::ty_vec(ref mt, None) => {
|
||||
heap_vec_metadata(cx, pointee_type, mt.ty, unique_type_id, usage_site_span)
|
||||
// FIXME Can we do better than this for unsized vec/str fields?
|
||||
ty::ty_vec(typ, None) => fixed_vec_metadata(cx, unique_type_id, typ, 0, usage_site_span),
|
||||
ty::ty_str => fixed_vec_metadata(cx, unique_type_id, ty::mk_i8(), 0, usage_site_span),
|
||||
ty::ty_trait(..) => {
|
||||
MetadataCreationResult::new(
|
||||
trait_pointer_metadata(cx, t, None, unique_type_id),
|
||||
false)
|
||||
}
|
||||
ty::ty_uniq(ty) | ty::ty_ptr(ty::mt{ty, ..}) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_vec(typ, None) => {
|
||||
vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)
|
||||
}
|
||||
ty::ty_str => {
|
||||
let i8_t = ty::mk_i8();
|
||||
heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span)
|
||||
vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span)
|
||||
}
|
||||
ty::ty_trait(..) => {
|
||||
MetadataCreationResult::new(
|
||||
trait_pointer_metadata(cx, t, unique_type_id),
|
||||
trait_pointer_metadata(cx, ty, Some(t), unique_type_id),
|
||||
false)
|
||||
}
|
||||
_ => {
|
||||
let pointee_metadata = type_metadata(cx,
|
||||
pointee_type,
|
||||
usage_site_span);
|
||||
let pointee_metadata = type_metadata(cx, ty, usage_site_span);
|
||||
|
||||
match debug_context(cx).type_map
|
||||
.borrow()
|
||||
.find_metadata_for_unique_id(unique_type_id) {
|
||||
@ -3022,33 +2937,6 @@ fn type_metadata(cx: &CrateContext,
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_ptr(ref mt) | ty::ty_rptr(_, ref mt) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(ref mt, None) => {
|
||||
vec_slice_metadata(cx, t, mt.ty, unique_type_id, usage_site_span)
|
||||
}
|
||||
ty::ty_str => {
|
||||
vec_slice_metadata(cx, t, ty::mk_u8(), unique_type_id, usage_site_span)
|
||||
}
|
||||
ty::ty_trait(..) => {
|
||||
MetadataCreationResult::new(
|
||||
trait_pointer_metadata(cx, t, unique_type_id),
|
||||
false)
|
||||
}
|
||||
_ => {
|
||||
let pointee = type_metadata(cx, mt.ty, usage_site_span);
|
||||
|
||||
match debug_context(cx).type_map
|
||||
.borrow()
|
||||
.find_metadata_for_unique_id(unique_type_id) {
|
||||
Some(metadata) => return metadata,
|
||||
None => { /* proceed normally */ }
|
||||
};
|
||||
|
||||
MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_bare_fn(ref barefnty) => {
|
||||
subroutine_type_metadata(cx, unique_type_id, &barefnty.sig, usage_site_span)
|
||||
}
|
||||
@ -3544,7 +3432,6 @@ fn populate_scope_map(cx: &CrateContext,
|
||||
ast::ExprAgain(_) |
|
||||
ast::ExprPath(_) => {}
|
||||
|
||||
ast::ExprVstore(ref sub_exp, _) |
|
||||
ast::ExprCast(ref sub_exp, _) |
|
||||
ast::ExprAddrOf(_, ref sub_exp) |
|
||||
ast::ExprField(ref sub_exp, _, _) |
|
||||
@ -3820,7 +3707,7 @@ fn push_debuginfo_type_name(cx: &CrateContext,
|
||||
|
||||
push_debuginfo_type_name(cx, inner_type, true, output);
|
||||
},
|
||||
ty::ty_vec(ty::mt { ty: inner_type, .. }, optional_length) => {
|
||||
ty::ty_vec(inner_type, optional_length) => {
|
||||
output.push_char('[');
|
||||
push_debuginfo_type_name(cx, inner_type, true, output);
|
||||
|
||||
@ -3933,6 +3820,7 @@ fn push_debuginfo_type_name(cx: &CrateContext,
|
||||
}
|
||||
ty::ty_err |
|
||||
ty::ty_infer(_) |
|
||||
ty::ty_open(_) |
|
||||
ty::ty_param(_) => {
|
||||
cx.sess().bug(format!("debuginfo: Trying to create type name for \
|
||||
unexpected type: {}", ppaux::ty_to_string(cx.tcx(), t)).as_slice());
|
||||
|
@ -40,6 +40,7 @@ use metadata::csearch;
|
||||
use middle::def;
|
||||
use middle::lang_items::MallocFnLangItem;
|
||||
use middle::mem_categorization::Typer;
|
||||
use middle::subst;
|
||||
use middle::trans::_match;
|
||||
use middle::trans::adt;
|
||||
use middle::trans::asm;
|
||||
@ -62,15 +63,15 @@ use middle::trans::inline;
|
||||
use middle::trans::tvec;
|
||||
use middle::trans::type_of;
|
||||
use middle::ty::struct_fields;
|
||||
use middle::ty::{AutoBorrowObj, AutoDerefRef, AutoAddEnv, AutoObject, AutoUnsafe};
|
||||
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef};
|
||||
use middle::ty::{AutoDerefRef, AutoAddEnv, AutoUnsafe};
|
||||
use middle::ty::{AutoPtr};
|
||||
use middle::ty;
|
||||
use middle::typeck;
|
||||
use middle::typeck::MethodCall;
|
||||
use util::common::indenter;
|
||||
use util::ppaux::Repr;
|
||||
use util::nodemap::NodeMap;
|
||||
use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_alloc};
|
||||
use middle::trans::machine::{llsize_of, llsize_of_alloc};
|
||||
use middle::trans::type_::Type;
|
||||
|
||||
use syntax::ast;
|
||||
@ -160,6 +161,14 @@ pub fn trans<'a>(bcx: &'a Block<'a>,
|
||||
return DatumBlock::new(bcx, datum);
|
||||
}
|
||||
|
||||
pub fn get_len(bcx: &Block, fat_ptr: ValueRef) -> ValueRef {
|
||||
GEPi(bcx, fat_ptr, [0u, abi::slice_elt_len])
|
||||
}
|
||||
|
||||
pub fn get_dataptr(bcx: &Block, fat_ptr: ValueRef) -> ValueRef {
|
||||
GEPi(bcx, fat_ptr, [0u, abi::slice_elt_base])
|
||||
}
|
||||
|
||||
fn apply_adjustments<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>)
|
||||
@ -184,71 +193,289 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
|
||||
datum = unpack_datum!(bcx, add_env(bcx, expr, datum));
|
||||
}
|
||||
AutoDerefRef(ref adj) => {
|
||||
if adj.autoderefs > 0 {
|
||||
let (autoderefs, use_autoref) = match adj.autoref {
|
||||
// Extracting a value from a box counts as a deref, but if we are
|
||||
// just converting Box<[T, ..n]> to Box<[T]> we aren't really doing
|
||||
// a deref (and wouldn't if we could treat Box like a normal struct).
|
||||
Some(ty::AutoUnsizeUniq(..)) => (adj.autoderefs - 1, true),
|
||||
// We are a bit paranoid about adjustments and thus might have a re-
|
||||
// borrow here which merely derefs and then refs again (it might have
|
||||
// a different region or mutability, but we don't care here. It might
|
||||
// also be just in case we need to unsize. But if there are no nested
|
||||
// adjustments then it should be a no-op).
|
||||
Some(ty::AutoPtr(_, _, None)) if adj.autoderefs == 1 => {
|
||||
match ty::get(datum.ty).sty {
|
||||
// Don't skip a conversion from Box<T> to &T, etc.
|
||||
ty::ty_rptr(..) => {
|
||||
let method_call = MethodCall::autoderef(expr.id, adj.autoderefs-1);
|
||||
let method = bcx.tcx().method_map.borrow().find(&method_call).is_some();
|
||||
if method {
|
||||
// Don't skip an overloaded deref.
|
||||
(adj.autoderefs, true)
|
||||
} else {
|
||||
(adj.autoderefs - 1, false)
|
||||
}
|
||||
}
|
||||
_ => (adj.autoderefs, true),
|
||||
}
|
||||
}
|
||||
_ => (adj.autoderefs, true)
|
||||
};
|
||||
|
||||
if autoderefs > 0 {
|
||||
// Schedule cleanup.
|
||||
let lval = unpack_datum!(bcx, datum.to_lvalue_datum(bcx, "auto_deref", expr.id));
|
||||
datum = unpack_datum!(
|
||||
bcx, deref_multiple(bcx, expr, datum, adj.autoderefs));
|
||||
bcx, deref_multiple(bcx, expr, lval.to_expr_datum(), autoderefs));
|
||||
}
|
||||
|
||||
datum = match adj.autoref {
|
||||
None => {
|
||||
datum
|
||||
// (You might think there is a more elegant way to do this than a
|
||||
// use_autoref bool, but then you remember that the borrow checker exists).
|
||||
match (use_autoref, &adj.autoref) {
|
||||
(true, &Some(ref a)) => {
|
||||
datum = unpack_datum!(bcx, apply_autoref(a,
|
||||
bcx,
|
||||
expr,
|
||||
datum));
|
||||
}
|
||||
Some(AutoUnsafe(..)) | // region + unsafe ptrs have same repr
|
||||
Some(AutoPtr(..)) => {
|
||||
unpack_datum!(bcx, auto_ref(bcx, datum, expr))
|
||||
}
|
||||
Some(AutoBorrowVec(..)) => {
|
||||
unpack_datum!(bcx, auto_slice(bcx, expr, datum))
|
||||
}
|
||||
Some(AutoBorrowVecRef(..)) => {
|
||||
unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum))
|
||||
}
|
||||
Some(AutoBorrowObj(..)) => {
|
||||
unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum))
|
||||
}
|
||||
};
|
||||
}
|
||||
AutoObject(..) => {
|
||||
let adjusted_ty = ty::expr_ty_adjusted(bcx.tcx(), expr);
|
||||
let scratch = rvalue_scratch_datum(bcx, adjusted_ty, "__adjust");
|
||||
bcx = meth::trans_trait_cast(
|
||||
bcx, datum, expr.id, SaveIn(scratch.val));
|
||||
datum = scratch.to_expr_datum();
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
debug!("after adjustments, datum={}", datum.to_string(bcx.ccx()));
|
||||
return DatumBlock {bcx: bcx, datum: datum};
|
||||
return DatumBlock::new(bcx, datum);
|
||||
|
||||
fn auto_slice<'a>(
|
||||
bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
// This is not the most efficient thing possible; since slices
|
||||
// are two words it'd be better if this were compiled in
|
||||
// 'dest' mode, but I can't find a nice way to structure the
|
||||
// code and keep it DRY that accommodates that use case at the
|
||||
// moment.
|
||||
fn apply_autoref<'a>(autoref: &ty::AutoRef,
|
||||
bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let mut bcx = bcx;
|
||||
let mut datum = datum;
|
||||
|
||||
let datum = match autoref {
|
||||
&AutoUnsafe(..) => {
|
||||
debug!(" AutoUnsafe");
|
||||
unpack_datum!(bcx, ref_ptr(bcx, expr, datum))
|
||||
}
|
||||
&AutoPtr(_, _, ref a) => {
|
||||
debug!(" AutoPtr");
|
||||
match a {
|
||||
&Some(box ref a) => datum = unpack_datum!(bcx,
|
||||
apply_autoref(a, bcx, expr, datum)),
|
||||
_ => {}
|
||||
}
|
||||
unpack_datum!(bcx, ref_ptr(bcx, expr, datum))
|
||||
}
|
||||
&ty::AutoUnsize(ref k) => {
|
||||
debug!(" AutoUnsize");
|
||||
unpack_datum!(bcx, unsize_expr(bcx, expr, datum, k))
|
||||
}
|
||||
|
||||
&ty::AutoUnsizeUniq(ty::UnsizeLength(len)) => {
|
||||
debug!(" AutoUnsizeUniq(UnsizeLength)");
|
||||
unpack_datum!(bcx, unsize_unique_vec(bcx, expr, datum, len))
|
||||
}
|
||||
&ty::AutoUnsizeUniq(ref k) => {
|
||||
debug!(" AutoUnsizeUniq");
|
||||
unpack_datum!(bcx, unsize_unique_expr(bcx, expr, datum, k))
|
||||
}
|
||||
};
|
||||
|
||||
DatumBlock::new(bcx, datum)
|
||||
}
|
||||
|
||||
fn ref_ptr<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
if !ty::type_is_sized(bcx.tcx(), datum.ty) {
|
||||
debug!("Taking address of unsized type {}",
|
||||
bcx.ty_to_string(datum.ty));
|
||||
ref_fat_ptr(bcx, expr, datum)
|
||||
} else {
|
||||
debug!("Taking address of sized type {}",
|
||||
bcx.ty_to_string(datum.ty));
|
||||
auto_ref(bcx, datum, expr)
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the information we are losing (making dynamic) in an unsizing
|
||||
// adjustment.
|
||||
// When making a dtor, we need to do different things depending on the
|
||||
// ownership of the object.. mk_ty is a function for turning unsized_type
|
||||
// into a type to be destructed. If we want to end up with a Box pointer,
|
||||
// then mk_ty should make a Box pointer (T -> Box<T>), if we want a
|
||||
// borrowed reference then it should be T -> &T.
|
||||
fn unsized_info<'a>(bcx: &'a Block<'a>,
|
||||
kind: &ty::UnsizeKind,
|
||||
id: ast::NodeId,
|
||||
unsized_ty: ty::t,
|
||||
mk_ty: |ty::t| -> ty::t) -> ValueRef {
|
||||
match kind {
|
||||
&ty::UnsizeLength(len) => C_uint(bcx.ccx(), len),
|
||||
&ty::UnsizeStruct(box ref k, tp_index) => match ty::get(unsized_ty).sty {
|
||||
ty::ty_struct(_, ref substs) => {
|
||||
let ty_substs = substs.types.get_slice(subst::TypeSpace);
|
||||
// The dtor for a field treats it like a value, so mk_ty
|
||||
// should just be the identity function.
|
||||
unsized_info(bcx, k, id, ty_substs[tp_index], |t| t)
|
||||
}
|
||||
_ => bcx.sess().bug(format!("UnsizeStruct with bad sty: {}",
|
||||
bcx.ty_to_string(unsized_ty)).as_slice())
|
||||
},
|
||||
&ty::UnsizeVtable(..) =>
|
||||
PointerCast(bcx,
|
||||
meth::vtable_ptr(bcx, id, mk_ty(unsized_ty)),
|
||||
Type::vtable_ptr(bcx.ccx()))
|
||||
}
|
||||
}
|
||||
|
||||
fn unsize_expr<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>,
|
||||
k: &ty::UnsizeKind)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let tcx = bcx.tcx();
|
||||
let datum_ty = datum.ty;
|
||||
let unsized_ty = ty::unsize_ty(tcx, datum_ty, k, expr.span);
|
||||
let dest_ty = ty::mk_open(tcx, unsized_ty);
|
||||
// Closures for extracting and manipulating the data and payload parts of
|
||||
// the fat pointer.
|
||||
let base = match k {
|
||||
&ty::UnsizeStruct(..) =>
|
||||
|bcx, val| PointerCast(bcx,
|
||||
val,
|
||||
type_of::type_of(bcx.ccx(), unsized_ty).ptr_to()),
|
||||
&ty::UnsizeLength(..) =>
|
||||
|bcx, val| GEPi(bcx, val, [0u, 0u]),
|
||||
&ty::UnsizeVtable(..) =>
|
||||
|_bcx, val| PointerCast(bcx, val, Type::i8p(bcx.ccx()))
|
||||
};
|
||||
let info = |bcx, _val| unsized_info(bcx,
|
||||
k,
|
||||
expr.id,
|
||||
ty::deref_or_dont(datum_ty),
|
||||
|t| ty::mk_rptr(tcx,
|
||||
ty::ReStatic,
|
||||
ty::mt{
|
||||
ty: t,
|
||||
mutbl: ast::MutImmutable
|
||||
}));
|
||||
into_fat_ptr(bcx, expr, datum, dest_ty, base, info)
|
||||
}
|
||||
|
||||
fn ref_fat_ptr<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let tcx = bcx.tcx();
|
||||
let dest_ty = ty::close_type(tcx, datum.ty);
|
||||
let base = |bcx, val| Load(bcx, get_dataptr(bcx, val));
|
||||
let len = |bcx, val| Load(bcx, get_len(bcx, val));
|
||||
into_fat_ptr(bcx, expr, datum, dest_ty, base, len)
|
||||
}
|
||||
|
||||
fn into_fat_ptr<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>,
|
||||
dest_ty: ty::t,
|
||||
base: |&'a Block<'a>, ValueRef| -> ValueRef,
|
||||
info: |&'a Block<'a>, ValueRef| -> ValueRef)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let mut bcx = bcx;
|
||||
|
||||
// Arrange cleanup
|
||||
let lval = unpack_datum!(bcx,
|
||||
datum.to_lvalue_datum(bcx, "into_fat_ptr", expr.id));
|
||||
let base = base(bcx, lval.val);
|
||||
let info = info(bcx, lval.val);
|
||||
|
||||
let scratch = rvalue_scratch_datum(bcx, dest_ty, "__fat_ptr");
|
||||
Store(bcx, base, get_dataptr(bcx, scratch.val));
|
||||
Store(bcx, info, get_len(bcx, scratch.val));
|
||||
|
||||
DatumBlock::new(bcx, scratch.to_expr_datum())
|
||||
}
|
||||
|
||||
fn unsize_unique_vec<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>,
|
||||
len: uint)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let mut bcx = bcx;
|
||||
let tcx = bcx.tcx();
|
||||
let unit_ty = ty::sequence_element_type(tcx, datum.ty);
|
||||
|
||||
// Arrange cleanup, if not already done. This is needed in
|
||||
// case we are auto-slicing an owned vector or some such.
|
||||
let datum = unpack_datum!(
|
||||
bcx, datum.to_lvalue_datum(bcx, "auto_slice", expr.id));
|
||||
let datum_ty = datum.ty;
|
||||
// Arrange cleanup
|
||||
let lval = unpack_datum!(bcx,
|
||||
datum.to_lvalue_datum(bcx, "unsize_unique_vec", expr.id));
|
||||
|
||||
let (base, len) = datum.get_vec_base_and_len(bcx);
|
||||
let ll_len = C_uint(bcx.ccx(), len);
|
||||
let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty));
|
||||
let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None));
|
||||
let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique");
|
||||
|
||||
// this type may have a different region/mutability than the
|
||||
// real one, but it will have the same runtime representation
|
||||
let slice_ty = ty::mk_slice(tcx, ty::ReStatic,
|
||||
ty::mt { ty: unit_ty, mutbl: ast::MutImmutable });
|
||||
if len == 0 {
|
||||
Store(bcx,
|
||||
C_null(type_of::type_of(bcx.ccx(), unit_ty).ptr_to()),
|
||||
get_dataptr(bcx, scratch.val));
|
||||
} else {
|
||||
// Box<[(), ..n]> will not allocate, but ~[()] expects an
|
||||
// allocation of n bytes, so we must allocate here (yuck).
|
||||
let llty = type_of::type_of(bcx.ccx(), unit_ty);
|
||||
if llsize_of_alloc(bcx.ccx(), llty) == 0 {
|
||||
let ptr_unit_ty = type_of::type_of(bcx.ccx(), unit_ty).ptr_to();
|
||||
let align = C_uint(bcx.ccx(), 8);
|
||||
let alloc_result = malloc_raw_dyn(bcx, ptr_unit_ty, vec_ty, ll_len, align);
|
||||
bcx = alloc_result.bcx;
|
||||
let base = get_dataptr(bcx, scratch.val);
|
||||
Store(bcx, alloc_result.val, base);
|
||||
} else {
|
||||
let base = get_dataptr(bcx, scratch.val);
|
||||
let base = PointerCast(bcx,
|
||||
base,
|
||||
type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
|
||||
bcx = lval.store_to(bcx, base);
|
||||
}
|
||||
}
|
||||
|
||||
Store(bcx, ll_len, get_len(bcx, scratch.val));
|
||||
DatumBlock::new(bcx, scratch.to_expr_datum())
|
||||
}
|
||||
|
||||
fn unsize_unique_expr<'a>(bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>,
|
||||
k: &ty::UnsizeKind)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let mut bcx = bcx;
|
||||
let tcx = bcx.tcx();
|
||||
|
||||
let datum_ty = datum.ty;
|
||||
let unboxed_ty = match ty::get(datum_ty).sty {
|
||||
ty::ty_uniq(t) => t,
|
||||
_ => bcx.sess().bug(format!("Expected ty_uniq, found {}",
|
||||
bcx.ty_to_string(datum_ty)).as_slice())
|
||||
};
|
||||
let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span));
|
||||
|
||||
let lval = unpack_datum!(bcx,
|
||||
datum.to_lvalue_datum(bcx, "unsize_unique_expr", expr.id));
|
||||
|
||||
let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr");
|
||||
let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty);
|
||||
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
|
||||
bcx = lval.store_to(bcx, base);
|
||||
|
||||
let info = unsized_info(bcx, k, expr.id, unboxed_ty, |t| ty::mk_uniq(tcx, t));
|
||||
Store(bcx, info, get_len(bcx, scratch.val));
|
||||
|
||||
let scratch = unpack_datum!(bcx,
|
||||
scratch.to_expr_datum().to_lvalue_datum(bcx,
|
||||
"fresh_uniq_fat_ptr",
|
||||
expr.id));
|
||||
|
||||
let scratch = rvalue_scratch_datum(bcx, slice_ty, "__adjust");
|
||||
Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
|
||||
Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
|
||||
DatumBlock::new(bcx, scratch.to_expr_datum())
|
||||
}
|
||||
|
||||
@ -267,32 +494,6 @@ fn apply_adjustments<'a>(bcx: &'a Block<'a>,
|
||||
let def = ty::resolve_expr(bcx.tcx(), expr);
|
||||
closure::make_closure_from_bare_fn(bcx, closure_ty, def, fn_ptr)
|
||||
}
|
||||
|
||||
fn auto_slice_and_ref<'a>(
|
||||
bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
datum: Datum<Expr>)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum);
|
||||
auto_ref(bcx, datum, expr)
|
||||
}
|
||||
|
||||
fn auto_borrow_obj<'a>(mut bcx: &'a Block<'a>,
|
||||
expr: &ast::Expr,
|
||||
source_datum: Datum<Expr>)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let tcx = bcx.tcx();
|
||||
let target_obj_ty = expr_ty_adjusted(bcx, expr);
|
||||
debug!("auto_borrow_obj(target={})", target_obj_ty.repr(tcx));
|
||||
|
||||
// Arrange cleanup, if not already done. This is needed in
|
||||
// case we are auto-borrowing a Box<Trait> to &Trait
|
||||
let datum = unpack_datum!(
|
||||
bcx, source_datum.to_lvalue_datum(bcx, "autoborrowobj", expr.id));
|
||||
let mut datum = datum.to_expr_datum();
|
||||
datum.ty = target_obj_ty;
|
||||
DatumBlock::new(bcx, datum)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn trans_to_lvalue<'a>(bcx: &'a Block<'a>,
|
||||
@ -398,20 +599,31 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
ast::ExprIndex(ref base, ref idx) => {
|
||||
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
|
||||
}
|
||||
ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => {
|
||||
fcx.push_ast_cleanup_scope(contents.id);
|
||||
let datum = unpack_datum!(
|
||||
bcx, tvec::trans_uniq_vstore(bcx, expr, &**contents));
|
||||
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
|
||||
DatumBlock::new(bcx, datum)
|
||||
}
|
||||
ast::ExprBox(_, ref contents) => {
|
||||
// Special case for `Box<T>` and `Gc<T>`
|
||||
let box_ty = expr_ty(bcx, expr);
|
||||
let contents_ty = expr_ty(bcx, &**contents);
|
||||
match ty::get(box_ty).sty {
|
||||
ty::ty_uniq(..) => {
|
||||
trans_uniq_expr(bcx, box_ty, &**contents, contents_ty)
|
||||
let is_vec = match contents.node {
|
||||
ast::ExprRepeat(..) | ast::ExprVec(..) => true,
|
||||
ast::ExprLit(lit) => match lit.node {
|
||||
ast::LitStr(..) => true,
|
||||
_ => false
|
||||
},
|
||||
_ => false
|
||||
};
|
||||
|
||||
if is_vec {
|
||||
// Special case for owned vectors.
|
||||
fcx.push_ast_cleanup_scope(contents.id);
|
||||
let datum = unpack_datum!(
|
||||
bcx, tvec::trans_uniq_vec(bcx, expr, &**contents));
|
||||
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id);
|
||||
DatumBlock::new(bcx, datum)
|
||||
} else {
|
||||
trans_uniq_expr(bcx, box_ty, &**contents, contents_ty)
|
||||
}
|
||||
}
|
||||
ty::ty_box(..) => {
|
||||
trans_managed_expr(bcx, box_ty, &**contents, contents_ty)
|
||||
@ -419,6 +631,7 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
_ => bcx.sess().span_bug(expr.span,
|
||||
"expected unique or managed box")
|
||||
}
|
||||
|
||||
}
|
||||
ast::ExprLit(ref lit) => trans_immediate_lit(bcx, expr, (**lit).clone()),
|
||||
ast::ExprBinary(op, ref lhs, ref rhs) => {
|
||||
@ -428,7 +641,19 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
trans_unary(bcx, expr, op, &**x)
|
||||
}
|
||||
ast::ExprAddrOf(_, ref x) => {
|
||||
trans_addr_of(bcx, expr, &**x)
|
||||
match x.node {
|
||||
ast::ExprRepeat(..) | ast::ExprVec(..) => {
|
||||
// Special case for slices.
|
||||
fcx.push_ast_cleanup_scope(x.id);
|
||||
let datum = unpack_datum!(
|
||||
bcx, tvec::trans_slice_vec(bcx, expr, &**x));
|
||||
bcx = fcx.pop_and_trans_ast_cleanup_scope(bcx, x.id);
|
||||
DatumBlock::new(bcx, datum)
|
||||
}
|
||||
_ => {
|
||||
trans_addr_of(bcx, expr, &**x)
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprCast(ref val, _) => {
|
||||
// Datum output mode means this is a scalar cast:
|
||||
@ -454,14 +679,27 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>,
|
||||
let _icx = push_ctxt("trans_rec_field");
|
||||
|
||||
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, base, "field"));
|
||||
let repr = adt::represent_type(bcx.ccx(), base_datum.ty);
|
||||
with_field_tys(bcx.tcx(), base_datum.ty, None, |discr, field_tys| {
|
||||
let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
|
||||
let d = base_datum.get_element(
|
||||
field_tys[ix].mt.ty,
|
||||
|srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
|
||||
let bare_ty = ty::unopen_type(base_datum.ty);
|
||||
let repr = adt::represent_type(bcx.ccx(), bare_ty);
|
||||
with_field_tys(bcx.tcx(), bare_ty, None, |discr, field_tys| {
|
||||
let ix = ty::field_idx_strict(bcx.tcx(), field.name, field_tys);
|
||||
let d = base_datum.get_element(
|
||||
bcx,
|
||||
field_tys[ix].mt.ty,
|
||||
|srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, ix));
|
||||
|
||||
if ty::type_is_sized(bcx.tcx(), d.ty) {
|
||||
DatumBlock { datum: d.to_expr_datum(), bcx: bcx }
|
||||
})
|
||||
} else {
|
||||
let scratch = rvalue_scratch_datum(bcx, ty::mk_open(bcx.tcx(), d.ty), "");
|
||||
Store(bcx, d.val, get_dataptr(bcx, scratch.val));
|
||||
let info = Load(bcx, get_len(bcx, base_datum.val));
|
||||
Store(bcx, info, get_len(bcx, scratch.val));
|
||||
|
||||
DatumBlock::new(bcx, scratch.to_expr_datum())
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn trans_index<'a>(bcx: &'a Block<'a>,
|
||||
@ -727,7 +965,6 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
let _icx = push_ctxt("trans_rvalue_dps_unadjusted");
|
||||
let mut bcx = bcx;
|
||||
let tcx = bcx.tcx();
|
||||
let fcx = bcx.fcx;
|
||||
|
||||
match expr.node {
|
||||
ast::ExprParen(ref e) => {
|
||||
@ -772,14 +1009,8 @@ fn trans_rvalue_dps_unadjusted<'a>(bcx: &'a Block<'a>,
|
||||
}
|
||||
}
|
||||
}
|
||||
ast::ExprVstore(ref contents, ast::ExprVstoreSlice) |
|
||||
ast::ExprVstore(ref contents, ast::ExprVstoreMutSlice) => {
|
||||
fcx.push_ast_cleanup_scope(contents.id);
|
||||
bcx = tvec::trans_slice_vstore(bcx, expr, &**contents, dest);
|
||||
fcx.pop_and_trans_ast_cleanup_scope(bcx, contents.id)
|
||||
}
|
||||
ast::ExprVec(..) | ast::ExprRepeat(..) => {
|
||||
tvec::trans_fixed_vstore(bcx, expr, expr, dest)
|
||||
tvec::trans_fixed_vstore(bcx, expr, dest)
|
||||
}
|
||||
ast::ExprFnBlock(_, ref decl, ref body) |
|
||||
ast::ExprProc(ref decl, ref body) => {
|
||||
@ -1146,7 +1377,8 @@ pub fn trans_adt<'a>(mut bcx: &'a Block<'a>,
|
||||
let base_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, &*base.expr, "base"));
|
||||
for &(i, t) in base.fields.iter() {
|
||||
let datum = base_datum.get_element(
|
||||
t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
|
||||
bcx, t, |srcval| adt::trans_field_ptr(bcx, &*repr, srcval, discr, i));
|
||||
assert!(ty::type_is_sized(bcx.tcx(), datum.ty));
|
||||
let dest = adt::trans_field_ptr(bcx, &*repr, addr, discr, i);
|
||||
bcx = datum.store_to(bcx, dest);
|
||||
}
|
||||
@ -1253,13 +1485,12 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
|
||||
-> DatumBlock<'a, Expr> {
|
||||
let _icx = push_ctxt("trans_uniq_expr");
|
||||
let fcx = bcx.fcx;
|
||||
assert!(ty::type_is_sized(bcx.tcx(), contents_ty));
|
||||
let llty = type_of::type_of(bcx.ccx(), contents_ty);
|
||||
let size = llsize_of(bcx.ccx(), llty);
|
||||
let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint);
|
||||
// We need to a make a pointer type because box_ty is ty_bot
|
||||
// if content_ty is, e.g. box fail!().
|
||||
let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
|
||||
let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align);
|
||||
let align = C_uint(bcx.ccx(), type_of::align_of(bcx.ccx(), contents_ty) as uint);
|
||||
let llty_ptr = llty.ptr_to();
|
||||
let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align);
|
||||
// Unique boxes do not allocate for zero-size types. The standard library
|
||||
// may assume that `free` is never called on the pointer returned for
|
||||
// `Box<ZeroSizeType>`.
|
||||
@ -1303,8 +1534,28 @@ fn trans_addr_of<'a>(bcx: &'a Block<'a>,
|
||||
let _icx = push_ctxt("trans_addr_of");
|
||||
let mut bcx = bcx;
|
||||
let sub_datum = unpack_datum!(bcx, trans_to_lvalue(bcx, subexpr, "addr_of"));
|
||||
let ty = expr_ty(bcx, expr);
|
||||
return immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock();
|
||||
match ty::get(sub_datum.ty).sty {
|
||||
ty::ty_open(_) => {
|
||||
// Opened DST value, close to a fat pointer
|
||||
debug!("Closing fat pointer {}", bcx.ty_to_string(sub_datum.ty));
|
||||
|
||||
let scratch = rvalue_scratch_datum(bcx,
|
||||
ty::close_type(bcx.tcx(), sub_datum.ty),
|
||||
"fat_addr_of");
|
||||
let base = Load(bcx, get_dataptr(bcx, sub_datum.val));
|
||||
Store(bcx, base, get_dataptr(bcx, scratch.val));
|
||||
|
||||
let len = Load(bcx, get_len(bcx, sub_datum.val));
|
||||
Store(bcx, len, get_len(bcx, scratch.val));
|
||||
|
||||
DatumBlock::new(bcx, scratch.to_expr_datum())
|
||||
}
|
||||
_ => {
|
||||
// Sized value, ref to a thin pointer
|
||||
let ty = expr_ty(bcx, expr);
|
||||
immediate_rvalue_bcx(bcx, sub_datum.val, ty).to_expr_datumblock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Important to get types for both lhs and rhs, because one might be _|_
|
||||
@ -1592,15 +1843,18 @@ pub enum cast_kind {
|
||||
cast_other,
|
||||
}
|
||||
|
||||
pub fn cast_type_kind(t: ty::t) -> cast_kind {
|
||||
pub fn cast_type_kind(tcx: &ty::ctxt, t: ty::t) -> cast_kind {
|
||||
match ty::get(t).sty {
|
||||
ty::ty_char => cast_integral,
|
||||
ty::ty_float(..) => cast_float,
|
||||
ty::ty_ptr(..) => cast_pointer,
|
||||
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty{
|
||||
ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => cast_other,
|
||||
_ => cast_pointer,
|
||||
},
|
||||
ty::ty_rptr(_, mt) => {
|
||||
if ty::type_is_sized(tcx, mt.ty) {
|
||||
cast_pointer
|
||||
} else {
|
||||
cast_other
|
||||
}
|
||||
}
|
||||
ty::ty_bare_fn(..) => cast_pointer,
|
||||
ty::ty_int(..) => cast_integral,
|
||||
ty::ty_uint(..) => cast_integral,
|
||||
@ -1620,8 +1874,8 @@ fn trans_imm_cast<'a>(bcx: &'a Block<'a>,
|
||||
|
||||
let t_in = expr_ty(bcx, expr);
|
||||
let t_out = node_id_type(bcx, id);
|
||||
let k_in = cast_type_kind(t_in);
|
||||
let k_out = cast_type_kind(t_out);
|
||||
let k_in = cast_type_kind(bcx.tcx(), t_in);
|
||||
let k_out = cast_type_kind(bcx.tcx(), t_out);
|
||||
let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
|
||||
let ll_t_in = type_of::arg_type_of(ccx, t_in);
|
||||
let ll_t_out = type_of::arg_type_of(ccx, t_out);
|
||||
@ -1809,10 +2063,14 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
|
||||
|
||||
let r = match ty::get(datum.ty).sty {
|
||||
ty::ty_uniq(content_ty) => {
|
||||
match ty::get(content_ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
|
||||
=> bcx.tcx().sess.span_bug(expr.span, "unexpected unsized box"),
|
||||
_ => deref_owned_pointer(bcx, expr, datum, content_ty),
|
||||
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
||||
deref_owned_pointer(bcx, expr, datum, content_ty)
|
||||
} else {
|
||||
// A fat pointer and an opened DST value have the same represenation
|
||||
// just different types.
|
||||
DatumBlock::new(bcx, Datum::new(datum.val,
|
||||
ty::mk_open(bcx.tcx(), content_ty),
|
||||
datum.kind))
|
||||
}
|
||||
}
|
||||
|
||||
@ -1827,21 +2085,21 @@ fn deref_once<'a>(bcx: &'a Block<'a>,
|
||||
|
||||
ty::ty_ptr(ty::mt { ty: content_ty, .. }) |
|
||||
ty::ty_rptr(_, ty::mt { ty: content_ty, .. }) => {
|
||||
match ty::get(content_ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..)
|
||||
=> bcx.tcx().sess.span_bug(expr.span, "unexpected unsized reference"),
|
||||
_ => {
|
||||
assert!(!ty::type_needs_drop(bcx.tcx(), datum.ty));
|
||||
if ty::type_is_sized(bcx.tcx(), content_ty) {
|
||||
let ptr = datum.to_llscalarish(bcx);
|
||||
|
||||
let ptr = datum.to_llscalarish(bcx);
|
||||
|
||||
// Always generate an lvalue datum, even if datum.mode is
|
||||
// an rvalue. This is because datum.mode is only an
|
||||
// rvalue for non-owning pointers like &T or *T, in which
|
||||
// case cleanup *is* scheduled elsewhere, by the true
|
||||
// owner (or, in the case of *T, by the user).
|
||||
DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
|
||||
}
|
||||
// Always generate an lvalue datum, even if datum.mode is
|
||||
// an rvalue. This is because datum.mode is only an
|
||||
// rvalue for non-owning pointers like &T or *T, in which
|
||||
// case cleanup *is* scheduled elsewhere, by the true
|
||||
// owner (or, in the case of *T, by the user).
|
||||
DatumBlock::new(bcx, Datum::new(ptr, content_ty, LvalueExpr))
|
||||
} else {
|
||||
// A fat pointer and an opened DST value have the same represenation
|
||||
// just different types.
|
||||
DatumBlock::new(bcx, Datum::new(datum.val,
|
||||
ty::mk_open(bcx.tcx(), content_ty),
|
||||
datum.kind))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@ use llvm::{ValueRef, True, get_param};
|
||||
use llvm;
|
||||
use middle::lang_items::{FreeFnLangItem, ExchangeFreeFnLangItem};
|
||||
use middle::subst;
|
||||
use middle::subst::Subst;
|
||||
use middle::trans::adt;
|
||||
use middle::trans::base::*;
|
||||
use middle::trans::build::*;
|
||||
@ -26,12 +27,13 @@ use middle::trans::callee;
|
||||
use middle::trans::cleanup;
|
||||
use middle::trans::cleanup::CleanupMethods;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::datum;
|
||||
use middle::trans::expr;
|
||||
use middle::trans::machine::*;
|
||||
use middle::trans::reflect;
|
||||
use middle::trans::tvec;
|
||||
use middle::trans::type_::Type;
|
||||
use middle::trans::type_of::{type_of, sizing_type_of};
|
||||
use middle::trans::type_of::{type_of, sizing_type_of, align_of};
|
||||
use middle::ty;
|
||||
use util::ppaux::ty_to_short_str;
|
||||
use util::ppaux;
|
||||
@ -51,24 +53,33 @@ pub fn trans_free<'a>(cx: &'a Block<'a>, v: ValueRef) -> &'a Block<'a> {
|
||||
Some(expr::Ignore)).bcx
|
||||
}
|
||||
|
||||
fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64,
|
||||
align: u64) -> &'a Block<'a> {
|
||||
fn trans_exchange_free_internal<'a>(cx: &'a Block<'a>, v: ValueRef, size: ValueRef,
|
||||
align: ValueRef) -> &'a Block<'a> {
|
||||
let _icx = push_ctxt("trans_exchange_free");
|
||||
let ccx = cx.ccx();
|
||||
callee::trans_lang_call(cx,
|
||||
langcall(cx, None, "", ExchangeFreeFnLangItem),
|
||||
[PointerCast(cx, v, Type::i8p(ccx)), C_uint(ccx, size as uint), C_uint(ccx, align as uint)],
|
||||
[PointerCast(cx, v, Type::i8p(ccx)), size, align],
|
||||
Some(expr::Ignore)).bcx
|
||||
}
|
||||
|
||||
pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64,
|
||||
align: u64) -> &'a Block<'a> {
|
||||
trans_exchange_free_internal(cx,
|
||||
v,
|
||||
C_uint(cx.ccx(), size as uint),
|
||||
C_uint(cx.ccx(), align as uint))
|
||||
}
|
||||
|
||||
pub fn trans_exchange_free_ty<'a>(bcx: &'a Block<'a>, ptr: ValueRef,
|
||||
content_ty: ty::t) -> &'a Block<'a> {
|
||||
assert!(ty::type_is_sized(bcx.ccx().tcx(), content_ty));
|
||||
let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
|
||||
let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
|
||||
|
||||
// `Box<ZeroSizeType>` does not allocate.
|
||||
if content_size != 0 {
|
||||
let content_align = llalign_of_min(bcx.ccx(), sizing_type);
|
||||
let content_align = align_of(bcx.ccx(), content_ty);
|
||||
trans_exchange_free(bcx, ptr, content_size, content_align)
|
||||
} else {
|
||||
bcx
|
||||
@ -91,6 +102,11 @@ pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||
|
||||
pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
|
||||
let tcx = ccx.tcx();
|
||||
// Even if there is no dtor for t, there might be one deeper down and we
|
||||
// might need to pass in the vtable ptr.
|
||||
if !ty::type_is_sized(tcx, t) {
|
||||
return t
|
||||
}
|
||||
if !ty::type_needs_drop(tcx, t) {
|
||||
return ty::mk_i8();
|
||||
}
|
||||
@ -98,18 +114,14 @@ pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
|
||||
ty::ty_box(typ) if !ty::type_needs_drop(tcx, typ) =>
|
||||
ty::mk_box(tcx, ty::mk_i8()),
|
||||
|
||||
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ) => {
|
||||
match ty::get(typ).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => t,
|
||||
_ => {
|
||||
let llty = sizing_type_of(ccx, typ);
|
||||
// `Box<ZeroSizeType>` does not allocate.
|
||||
if llsize_of_alloc(ccx, llty) == 0 {
|
||||
ty::mk_i8()
|
||||
} else {
|
||||
ty::mk_uniq(tcx, ty::mk_i8())
|
||||
}
|
||||
}
|
||||
ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ)
|
||||
&& ty::type_is_sized(tcx, typ) => {
|
||||
let llty = sizing_type_of(ccx, typ);
|
||||
// `Box<ZeroSizeType>` does not allocate.
|
||||
if llsize_of_alloc(ccx, llty) == 0 {
|
||||
ty::mk_i8()
|
||||
} else {
|
||||
ty::mk_uniq(tcx, ty::mk_i8())
|
||||
}
|
||||
}
|
||||
_ => t
|
||||
@ -120,8 +132,8 @@ pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||
-> &'a Block<'a> {
|
||||
// NB: v is an *alias* of type t here, not a direct value.
|
||||
let _icx = push_ctxt("drop_ty");
|
||||
let ccx = bcx.ccx();
|
||||
if ty::type_needs_drop(bcx.tcx(), t) {
|
||||
let ccx = bcx.ccx();
|
||||
let glue = get_drop_glue(ccx, t);
|
||||
let glue_type = get_drop_glue_type(ccx, t);
|
||||
let ptr = if glue_type != t {
|
||||
@ -143,13 +155,21 @@ pub fn drop_ty_immediate<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
|
||||
}
|
||||
|
||||
pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef {
|
||||
debug!("make drop glue for {}", ppaux::ty_to_string(ccx.tcx(), t));
|
||||
let t = get_drop_glue_type(ccx, t);
|
||||
debug!("drop glue type {}", ppaux::ty_to_string(ccx.tcx(), t));
|
||||
match ccx.drop_glues.borrow().find(&t) {
|
||||
Some(&glue) => return glue,
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let llfnty = Type::glue_fn(ccx, type_of(ccx, t).ptr_to());
|
||||
let llty = if ty::type_is_sized(ccx.tcx(), t) {
|
||||
type_of(ccx, t).ptr_to()
|
||||
} else {
|
||||
type_of(ccx, ty::mk_uniq(ccx.tcx(), t)).ptr_to()
|
||||
};
|
||||
|
||||
let llfnty = Type::glue_fn(ccx, llty);
|
||||
let glue = declare_generic_glue(ccx, t, llfnty, "drop");
|
||||
|
||||
ccx.drop_glues.borrow_mut().insert(t, glue);
|
||||
@ -212,7 +232,13 @@ fn trans_struct_drop_flag<'a>(mut bcx: &'a Block<'a>,
|
||||
substs: &subst::Substs)
|
||||
-> &'a Block<'a> {
|
||||
let repr = adt::represent_type(bcx.ccx(), t);
|
||||
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, v0));
|
||||
let struct_data = if ty::type_is_sized(bcx.tcx(), t) {
|
||||
v0
|
||||
} else {
|
||||
let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]);
|
||||
Load(bcx, llval)
|
||||
};
|
||||
let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
|
||||
with_cond(bcx, load_ty(bcx, drop_flag.val, ty::mk_bool()), |cx| {
|
||||
trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
|
||||
})
|
||||
@ -231,13 +257,31 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
|
||||
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t,
|
||||
class_did, substs);
|
||||
|
||||
// The second argument is the "self" argument for drop
|
||||
// The first argument is the "self" argument for drop
|
||||
let params = unsafe {
|
||||
let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
|
||||
ty.element_type().func_params()
|
||||
};
|
||||
|
||||
adt::fold_variants(bcx, &*repr, v0, |variant_cx, st, value| {
|
||||
let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs);
|
||||
let self_ty = match ty::get(fty).sty {
|
||||
ty::ty_bare_fn(ref f) => {
|
||||
assert!(f.sig.inputs.len() == 1);
|
||||
f.sig.inputs[0]
|
||||
}
|
||||
_ => bcx.sess().bug(format!("Expected function type, found {}",
|
||||
bcx.ty_to_string(fty)).as_slice())
|
||||
};
|
||||
|
||||
let (struct_data, info) = if ty::type_is_sized(bcx.tcx(), t) {
|
||||
(v0, None)
|
||||
} else {
|
||||
let data = GEPi(bcx, v0, [0, abi::slice_elt_base]);
|
||||
let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
|
||||
(Load(bcx, data), Some(Load(bcx, info)))
|
||||
};
|
||||
|
||||
adt::fold_variants(bcx, &*repr, struct_data, |variant_cx, st, value| {
|
||||
// Be sure to put all of the fields into a scope so we can use an invoke
|
||||
// instruction to call the user destructor but still call the field
|
||||
// destructors if the user destructor fails.
|
||||
@ -246,7 +290,22 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
|
||||
// Class dtors have no explicit args, so the params should
|
||||
// just consist of the environment (self).
|
||||
assert_eq!(params.len(), 1);
|
||||
let self_arg = PointerCast(variant_cx, value, *params.get(0));
|
||||
let self_arg = if ty::type_is_fat_ptr(bcx.tcx(), self_ty) {
|
||||
// The dtor expects a fat pointer, so make one, even if we have to fake it.
|
||||
let boxed_ty = ty::mk_open(bcx.tcx(), t);
|
||||
let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_self");
|
||||
Store(bcx, value, GEPi(bcx, scratch.val, [0, abi::slice_elt_base]));
|
||||
Store(bcx,
|
||||
// If we just had a thin pointer, make a fat pointer by sticking
|
||||
// null where we put the unsizing info. This works because t
|
||||
// is a sized type, so we will only unpack the fat pointer, never
|
||||
// use the fake info.
|
||||
info.unwrap_or(C_null(Type::i8p(bcx.ccx()))),
|
||||
GEPi(bcx, scratch.val, [0, abi::slice_elt_len]));
|
||||
PointerCast(variant_cx, scratch.val, *params.get(0))
|
||||
} else {
|
||||
PointerCast(variant_cx, value, *params.get(0))
|
||||
};
|
||||
let args = vec!(self_arg);
|
||||
|
||||
// Add all the fields as a value which needs to be cleaned at the end of
|
||||
@ -254,19 +313,84 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
|
||||
// the order in which fields get dropped.
|
||||
for (i, ty) in st.fields.iter().enumerate().rev() {
|
||||
let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
|
||||
|
||||
let val = if ty::type_is_sized(bcx.tcx(), *ty) {
|
||||
llfld_a
|
||||
} else {
|
||||
let boxed_ty = ty::mk_open(bcx.tcx(), *ty);
|
||||
let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_field");
|
||||
Store(bcx, llfld_a, GEPi(bcx, scratch.val, [0, abi::slice_elt_base]));
|
||||
Store(bcx, info.unwrap(), GEPi(bcx, scratch.val, [0, abi::slice_elt_len]));
|
||||
scratch.val
|
||||
};
|
||||
variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
|
||||
llfld_a, *ty);
|
||||
val, *ty);
|
||||
}
|
||||
|
||||
let dtor_ty = ty::mk_ctor_fn(variant_cx.tcx(), ast::DUMMY_NODE_ID,
|
||||
[get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
|
||||
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None);
|
||||
let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None, false);
|
||||
|
||||
variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
|
||||
variant_cx
|
||||
})
|
||||
}
|
||||
|
||||
fn size_and_align_of_dst<'a>(bcx: &'a Block<'a>, t :ty::t, info: ValueRef) -> (ValueRef, ValueRef) {
|
||||
debug!("calculate size of DST: {}; with lost info: {}",
|
||||
bcx.ty_to_string(t), bcx.val_to_string(info));
|
||||
if ty::type_is_sized(bcx.tcx(), t) {
|
||||
let sizing_type = sizing_type_of(bcx.ccx(), t);
|
||||
let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type) as uint);
|
||||
let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t) as uint);
|
||||
return (size, align);
|
||||
}
|
||||
match ty::get(t).sty {
|
||||
ty::ty_struct(id, ref substs) => {
|
||||
let ccx = bcx.ccx();
|
||||
// First get the size of all statically known fields.
|
||||
// Don't use type_of::sizing_type_of because that expects t to be sized.
|
||||
assert!(!ty::type_is_simd(bcx.tcx(), t));
|
||||
let repr = adt::represent_type(ccx, t);
|
||||
let sizing_type = adt::sizing_type_of(ccx, &*repr, true);
|
||||
let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type) as uint);
|
||||
let sized_align = C_uint(ccx, llalign_of_min(ccx, sizing_type) as uint);
|
||||
|
||||
// Recurse to get the size of the dynamically sized field (must be
|
||||
// the last field).
|
||||
let fields = ty::struct_fields(bcx.tcx(), id, substs);
|
||||
let last_field = fields[fields.len()-1];
|
||||
let field_ty = last_field.mt.ty;
|
||||
let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
|
||||
|
||||
// Return the sum of sizes and max of aligns.
|
||||
let size = Add(bcx, sized_size, unsized_size);
|
||||
let align = Select(bcx,
|
||||
ICmp(bcx, llvm::IntULT, sized_align, unsized_align),
|
||||
sized_align,
|
||||
unsized_align);
|
||||
(size, align)
|
||||
}
|
||||
ty::ty_trait(..) => {
|
||||
// info points to the vtable and the second entry in the vtable is the
|
||||
// dynamic size of the object.
|
||||
let info = PointerCast(bcx, info, Type::int(bcx.ccx()).ptr_to());
|
||||
let size_ptr = GEPi(bcx, info, [1u]);
|
||||
let align_ptr = GEPi(bcx, info, [2u]);
|
||||
(Load(bcx, size_ptr), Load(bcx, align_ptr))
|
||||
}
|
||||
ty::ty_vec(unit_ty, None) => {
|
||||
// The info in this case is the length of the vec, so the size is that
|
||||
// times the unit size.
|
||||
let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
|
||||
let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
|
||||
(Mul(bcx, info, C_uint(bcx.ccx(), unit_size as uint)), C_uint(bcx.ccx(), 8))
|
||||
}
|
||||
_ => bcx.sess().bug(format!("Unexpected unsized type, found {}",
|
||||
bcx.ty_to_string(t)).as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'a> {
|
||||
// NB: v0 is an *alias* of type t here, not a direct value.
|
||||
let _icx = push_ctxt("make_drop_glue");
|
||||
@ -276,29 +400,18 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
|
||||
}
|
||||
ty::ty_uniq(content_ty) => {
|
||||
match ty::get(content_ty).sty {
|
||||
ty::ty_vec(mt, None) => {
|
||||
let llbox = Load(bcx, v0);
|
||||
let not_null = IsNotNull(bcx, llbox);
|
||||
with_cond(bcx, not_null, |bcx| {
|
||||
let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, mt.ty);
|
||||
// FIXME: #13994: the old `Box<[T]>` will not support sized deallocation
|
||||
trans_exchange_free(bcx, llbox, 0, 8)
|
||||
})
|
||||
ty::ty_vec(ty, None) => {
|
||||
tvec::make_drop_glue_unboxed(bcx, v0, ty)
|
||||
}
|
||||
ty::ty_str => {
|
||||
let llbox = Load(bcx, v0);
|
||||
let not_null = IsNotNull(bcx, llbox);
|
||||
with_cond(bcx, not_null, |bcx| {
|
||||
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
|
||||
let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, unit_ty);
|
||||
// FIXME: #13994: the old `Box<str>` will not support sized deallocation
|
||||
trans_exchange_free(bcx, llbox, 0, 8)
|
||||
})
|
||||
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
|
||||
tvec::make_drop_glue_unboxed(bcx, v0, unit_ty)
|
||||
}
|
||||
ty::ty_trait(..) => {
|
||||
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
|
||||
// Only drop the value when it is non-null
|
||||
with_cond(bcx, IsNotNull(bcx, Load(bcx, lluniquevalue)), |bcx| {
|
||||
let concrete_ptr = Load(bcx, lluniquevalue);
|
||||
with_cond(bcx, IsNotNull(bcx, concrete_ptr), |bcx| {
|
||||
let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
|
||||
let dtor = Load(bcx, dtor_ptr);
|
||||
Call(bcx,
|
||||
@ -308,8 +421,22 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
|
||||
bcx
|
||||
})
|
||||
}
|
||||
ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), content_ty) => {
|
||||
let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]);
|
||||
let llbox = Load(bcx, llval);
|
||||
let not_null = IsNotNull(bcx, llbox);
|
||||
with_cond(bcx, not_null, |bcx| {
|
||||
let bcx = drop_ty(bcx, v0, content_ty);
|
||||
let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
|
||||
let info = Load(bcx, info);
|
||||
let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
|
||||
trans_exchange_free_internal(bcx, llbox, llsize, llalign)
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
let llbox = Load(bcx, v0);
|
||||
assert!(ty::type_is_sized(bcx.tcx(), content_ty));
|
||||
let llval = v0;
|
||||
let llbox = Load(bcx, llval);
|
||||
let not_null = IsNotNull(bcx, llbox);
|
||||
with_cond(bcx, not_null, |bcx| {
|
||||
let bcx = drop_ty(bcx, llbox, content_ty);
|
||||
@ -322,7 +449,21 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
|
||||
let tcx = bcx.tcx();
|
||||
match ty::ty_dtor(tcx, did) {
|
||||
ty::TraitDtor(dtor, true) => {
|
||||
trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
|
||||
// FIXME(16758) Since the struct is unsized, it is hard to
|
||||
// find the drop flag (which is at the end of the struct).
|
||||
// Lets just ignore the flag and pretend everything will be
|
||||
// OK.
|
||||
if ty::type_is_sized(bcx.tcx(), t) {
|
||||
trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
|
||||
} else {
|
||||
// Give the user a heads up that we are doing something
|
||||
// stupid and dangerous.
|
||||
bcx.sess().warn(format!("Ignoring drop flag in destructor for {}\
|
||||
because the struct is unsized. See issue\
|
||||
#16758",
|
||||
bcx.ty_to_string(t)).as_slice());
|
||||
trans_struct_drop(bcx, t, v0, dtor, did, substs)
|
||||
}
|
||||
}
|
||||
ty::TraitDtor(dtor, false) => {
|
||||
trans_struct_drop(bcx, t, v0, dtor, did, substs)
|
||||
@ -350,7 +491,23 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
|
||||
trans_exchange_free(bcx, env, 0, 8)
|
||||
})
|
||||
}
|
||||
ty::ty_trait(..) => {
|
||||
// No need to do a null check here (as opposed to the Box<trait case
|
||||
// above), because this happens for a trait field in an unsized
|
||||
// struct. If anything is null, it is the whole struct and we won't
|
||||
// get here.
|
||||
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
|
||||
let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
|
||||
let dtor = Load(bcx, dtor_ptr);
|
||||
Call(bcx,
|
||||
dtor,
|
||||
[PointerCast(bcx, Load(bcx, lluniquevalue), Type::i8p(bcx.ccx()))],
|
||||
None);
|
||||
bcx
|
||||
}
|
||||
ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty),
|
||||
_ => {
|
||||
assert!(ty::type_is_sized(bcx.tcx(), t));
|
||||
if ty::type_needs_drop(bcx.tcx(), t) &&
|
||||
ty::type_is_structural(t) {
|
||||
iter_structural_ty(bcx, v0, t, drop_ty)
|
||||
@ -449,7 +606,6 @@ fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
|
||||
ccx,
|
||||
t,
|
||||
format!("glue_{}", name).as_slice());
|
||||
debug!("{} is for type {}", fn_nm, ppaux::ty_to_string(ccx.tcx(), t));
|
||||
let llfn = decl_cdecl_fn(ccx, fn_nm.as_slice(), llfnty, ty::mk_nil());
|
||||
note_unique_llvm_symbol(ccx, fn_nm);
|
||||
return llfn;
|
||||
|
@ -119,6 +119,17 @@ pub fn check_intrinsics(ccx: &CrateContext) {
|
||||
"s"
|
||||
}).as_slice());
|
||||
}
|
||||
if ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.to) ||
|
||||
ty::type_is_fat_ptr(ccx.tcx(), transmute_restriction.from) {
|
||||
ccx.sess()
|
||||
.add_lint(::lint::builtin::TRANSMUTE_FAT_PTR,
|
||||
transmute_restriction.id,
|
||||
transmute_restriction.span,
|
||||
format!("Transmuting fat pointer types; {} to {}.\
|
||||
Beware of relying on the compiler's representation",
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.from),
|
||||
ty_to_string(ccx.tcx(), transmute_restriction.to)));
|
||||
}
|
||||
}
|
||||
ccx.sess().abort_if_errors();
|
||||
}
|
||||
@ -227,8 +238,7 @@ pub fn trans_intrinsic_call<'a>(mut bcx: &'a Block<'a>, node: ast::NodeId,
|
||||
}
|
||||
(_, "min_align_of") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
C_uint(ccx, machine::llalign_of_min(ccx, lltp_ty) as uint)
|
||||
C_uint(ccx, type_of::align_of(ccx, tp_ty) as uint)
|
||||
}
|
||||
(_, "pref_align_of") => {
|
||||
let tp_ty = *substs.types.get(FnSpace, 0);
|
||||
@ -542,7 +552,7 @@ fn copy_intrinsic(bcx: &Block, allow_overlap: bool, volatile: bool,
|
||||
tp_ty: ty::t, dst: ValueRef, src: ValueRef, count: ValueRef) -> ValueRef {
|
||||
let ccx = bcx.ccx();
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
let align = C_i32(ccx, machine::llalign_of_min(ccx, lltp_ty) as i32);
|
||||
let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
|
||||
let size = machine::llsize_of(ccx, lltp_ty);
|
||||
let int_size = machine::llbitsize_of_real(ccx, ccx.int_type);
|
||||
let name = if allow_overlap {
|
||||
@ -571,7 +581,7 @@ fn memset_intrinsic(bcx: &Block, volatile: bool, tp_ty: ty::t,
|
||||
dst: ValueRef, val: ValueRef, count: ValueRef) -> ValueRef {
|
||||
let ccx = bcx.ccx();
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
let align = C_i32(ccx, machine::llalign_of_min(ccx, lltp_ty) as i32);
|
||||
let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
|
||||
let size = machine::llsize_of(ccx, lltp_ty);
|
||||
let name = if machine::llbitsize_of_real(ccx, ccx.int_type) == 32 {
|
||||
"llvm.memset.p0i8.i32"
|
||||
|
@ -25,6 +25,7 @@ use middle::trans::datum::*;
|
||||
use middle::trans::expr::{SaveIn, Ignore};
|
||||
use middle::trans::expr;
|
||||
use middle::trans::glue;
|
||||
use middle::trans::machine;
|
||||
use middle::trans::monomorphize;
|
||||
use middle::trans::type_::Type;
|
||||
use middle::trans::type_of::*;
|
||||
@ -40,6 +41,9 @@ use syntax::parse::token;
|
||||
use syntax::{ast, ast_map, visit};
|
||||
use syntax::ast_util::PostExpansionMethod;
|
||||
|
||||
// drop_glue pointer, size, align.
|
||||
static VTABLE_OFFSET: uint = 3;
|
||||
|
||||
/**
|
||||
The main "translation" pass for methods. Generates code
|
||||
for non-monomorphized methods only. Other methods will
|
||||
@ -450,7 +454,7 @@ pub fn trans_trait_callee_from_llval<'a>(bcx: &'a Block<'a>,
|
||||
GEPi(bcx, llpair,
|
||||
[0u, abi::trt_field_vtable]),
|
||||
Type::vtable(ccx).ptr_to().ptr_to()));
|
||||
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + 1]));
|
||||
let mptr = Load(bcx, GEPi(bcx, llvtable, [0u, n_method + VTABLE_OFFSET]));
|
||||
let mptr = PointerCast(bcx, mptr, llcallee_ty.ptr_to());
|
||||
|
||||
return Callee {
|
||||
@ -580,9 +584,15 @@ fn get_vtable(bcx: &Block,
|
||||
}
|
||||
});
|
||||
|
||||
let size_ty = sizing_type_of(ccx, self_ty);
|
||||
let size = machine::llsize_of_alloc(ccx, size_ty);
|
||||
let ll_size = C_uint(ccx, size as uint);
|
||||
let align = align_of(ccx, self_ty);
|
||||
let ll_align = C_uint(ccx, align as uint);
|
||||
|
||||
// Generate a destructor for the vtable.
|
||||
let drop_glue = glue::get_drop_glue(ccx, self_ty);
|
||||
let vtable = make_vtable(ccx, drop_glue, methods);
|
||||
let vtable = make_vtable(ccx, drop_glue, ll_size, ll_align, methods);
|
||||
|
||||
ccx.vtables.borrow_mut().insert(hash_id, vtable);
|
||||
vtable
|
||||
@ -591,11 +601,14 @@ fn get_vtable(bcx: &Block,
|
||||
/// Helper function to declare and initialize the vtable.
|
||||
pub fn make_vtable<I: Iterator<ValueRef>>(ccx: &CrateContext,
|
||||
drop_glue: ValueRef,
|
||||
size: ValueRef,
|
||||
align: ValueRef,
|
||||
ptrs: I)
|
||||
-> ValueRef {
|
||||
let _icx = push_ctxt("meth::make_vtable");
|
||||
|
||||
let components: Vec<_> = Some(drop_glue).move_iter().chain(ptrs).collect();
|
||||
let head = vec![drop_glue, size, align];
|
||||
let components: Vec<_> = head.move_iter().chain(ptrs).collect();
|
||||
|
||||
unsafe {
|
||||
let tbl = C_struct(ccx, components.as_slice(), false);
|
||||
@ -666,6 +679,26 @@ fn emit_vtable_methods(bcx: &Block,
|
||||
}).collect()
|
||||
}
|
||||
|
||||
pub fn vtable_ptr<'a>(bcx: &'a Block<'a>,
|
||||
id: ast::NodeId,
|
||||
self_ty: ty::t) -> ValueRef {
|
||||
let ccx = bcx.ccx();
|
||||
let origins = {
|
||||
let vtable_map = ccx.tcx.vtable_map.borrow();
|
||||
// This trait cast might be because of implicit coercion
|
||||
let adjs = ccx.tcx.adjustments.borrow();
|
||||
let adjust = adjs.find(&id);
|
||||
let method_call = if adjust.is_some() && ty::adjust_is_object(adjust.unwrap()) {
|
||||
MethodCall::autoobject(id)
|
||||
} else {
|
||||
MethodCall::expr(id)
|
||||
};
|
||||
let vres = vtable_map.get(&method_call).get_self().unwrap();
|
||||
resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres)
|
||||
};
|
||||
get_vtable(bcx, self_ty, origins)
|
||||
}
|
||||
|
||||
pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>,
|
||||
datum: Datum<Expr>,
|
||||
id: ast::NodeId,
|
||||
@ -688,27 +721,16 @@ pub fn trans_trait_cast<'a>(bcx: &'a Block<'a>,
|
||||
SaveIn(dest) => dest
|
||||
};
|
||||
|
||||
let ccx = bcx.ccx();
|
||||
let v_ty = datum.ty;
|
||||
let llbox_ty = type_of(bcx.ccx(), datum.ty);
|
||||
let llbox_ty = type_of(bcx.ccx(), v_ty);
|
||||
|
||||
// Store the pointer into the first half of pair.
|
||||
let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]);
|
||||
llboxdest = PointerCast(bcx, llboxdest, llbox_ty.ptr_to());
|
||||
let llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]);
|
||||
let llboxdest = PointerCast(bcx, llboxdest, llbox_ty.ptr_to());
|
||||
bcx = datum.store_to(bcx, llboxdest);
|
||||
|
||||
// Store the vtable into the second half of pair.
|
||||
let origins = {
|
||||
let vtable_map = ccx.tcx.vtable_map.borrow();
|
||||
// This trait cast might be because of implicit coercion
|
||||
let method_call = match ccx.tcx.adjustments.borrow().find(&id) {
|
||||
Some(&ty::AutoObject(..)) => MethodCall::autoobject(id),
|
||||
_ => MethodCall::expr(id)
|
||||
};
|
||||
let vres = vtable_map.get(&method_call).get_self().unwrap();
|
||||
resolve_param_vtables_under_param_substs(ccx.tcx(), bcx.fcx.param_substs, vres)
|
||||
};
|
||||
let vtable = get_vtable(bcx, v_ty, origins);
|
||||
let vtable = vtable_ptr(bcx, id, v_ty);
|
||||
let llvtabledest = GEPi(bcx, lldest, [0u, abi::trt_field_vtable]);
|
||||
let llvtabledest = PointerCast(bcx, llvtabledest, val_ty(vtable).ptr_to());
|
||||
Store(bcx, vtable, llvtabledest);
|
||||
|
@ -66,7 +66,7 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
pub fn c_size_and_align(&mut self, t: ty::t) -> Vec<ValueRef> {
|
||||
let tr = type_of(self.bcx.ccx(), t);
|
||||
let s = machine::llsize_of_real(self.bcx.ccx(), tr);
|
||||
let a = machine::llalign_of_min(self.bcx.ccx(), tr);
|
||||
let a = align_of(self.bcx.ccx(), t);
|
||||
return vec!(self.c_uint(s as uint),
|
||||
self.c_uint(a as uint));
|
||||
}
|
||||
@ -94,6 +94,7 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
ty::MethodTraitItem(ref method) => (*method).clone(),
|
||||
};
|
||||
let mth_ty = ty::mk_bare_fn(tcx, method.fty.clone());
|
||||
debug!("Emit call visit method: visit_{}: {}", ty_name, ty_to_string(tcx, mth_ty));
|
||||
let v = self.visitor_val;
|
||||
debug!("passing {} args:", args.len());
|
||||
let mut bcx = self.bcx;
|
||||
@ -149,13 +150,24 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
ty::ty_float(ast::TyF32) => self.leaf("f32"),
|
||||
ty::ty_float(ast::TyF64) => self.leaf("f64"),
|
||||
|
||||
ty::ty_open(_) | ty::ty_str | ty::ty_vec(_, None) | ty::ty_trait(..) => {
|
||||
// Unfortunately we can't do anything here because at runtime we
|
||||
// pass around the value by pointer (*u8). But unsized pointers are
|
||||
// fat and so we can't just cast them to *u8 and back. So we have
|
||||
// to work with the pointer directly (see ty_rptr/ty_uniq).
|
||||
fail!("Can't reflect unsized type")
|
||||
}
|
||||
// FIXME(15049) Reflection for unsized structs.
|
||||
ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), t) => {
|
||||
fail!("Can't reflect unsized type")
|
||||
}
|
||||
|
||||
// Should rename to vec_*.
|
||||
ty::ty_vec(ref mt, Some(sz)) => {
|
||||
let extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice());
|
||||
let extra = extra.append(self.c_mt(mt).as_slice());
|
||||
ty::ty_vec(ty, Some(sz)) => {
|
||||
let mut extra = (vec!(self.c_uint(sz))).append(self.c_size_and_align(t).as_slice());
|
||||
extra.push(self.c_tydesc(ty));
|
||||
self.visit("evec_fixed", extra.as_slice())
|
||||
}
|
||||
ty::ty_vec(..) | ty::ty_str | ty::ty_trait(..) => fail!("unexpected unsized type"),
|
||||
// Should remove mt from box and uniq.
|
||||
ty::ty_box(typ) => {
|
||||
let extra = self.c_mt(&ty::mt {
|
||||
@ -164,14 +176,12 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
});
|
||||
self.visit("box", extra.as_slice())
|
||||
}
|
||||
ty::ty_ptr(ref mt) => {
|
||||
let extra = self.c_mt(mt);
|
||||
self.visit("ptr", extra.as_slice())
|
||||
}
|
||||
ty::ty_uniq(typ) => {
|
||||
match ty::get(typ).sty {
|
||||
ty::ty_vec(ref mt, None) => {
|
||||
let extra = Vec::new();
|
||||
let extra = extra.append(self.c_mt(mt).as_slice());
|
||||
self.visit("evec_uniq", extra.as_slice())
|
||||
}
|
||||
ty::ty_str => self.visit("estr_uniq", &[]),
|
||||
ty::ty_trait(..) => {
|
||||
let extra = [
|
||||
self.c_slice(token::intern_and_get_ident(
|
||||
@ -179,6 +189,12 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
];
|
||||
self.visit("trait", extra);
|
||||
}
|
||||
// FIXME(15049) allow reflection of Box<[T]>. You'll need to
|
||||
// restore visit_evec_uniq.
|
||||
ty::ty_vec(_, None) => {
|
||||
fail!("Box<[T]> theoretically doesn't exist, so don't try to reflect it")
|
||||
}
|
||||
ty::ty_str => fail!("Can't reflect Box<str> which shouldn't be used anyway"),
|
||||
_ => {
|
||||
let extra = self.c_mt(&ty::mt {
|
||||
ty: typ,
|
||||
@ -188,17 +204,11 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::ty_ptr(ref mt) => {
|
||||
let extra = self.c_mt(mt);
|
||||
self.visit("ptr", extra.as_slice())
|
||||
}
|
||||
ty::ty_rptr(_, ref mt) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(ref mt, None) => {
|
||||
let (name, extra) = ("slice".to_string(), Vec::new());
|
||||
let extra = extra.append(self.c_mt(mt).as_slice());
|
||||
self.visit(format!("evec_{}", name).as_slice(),
|
||||
extra.as_slice())
|
||||
ty::ty_vec(ty, None) => {
|
||||
let extra = self.c_mt(&ty::mt{ty: ty, mutbl: mt.mutbl});
|
||||
self.visit("evec_slice", extra.as_slice())
|
||||
}
|
||||
ty::ty_str => self.visit("estr_slice", &[]),
|
||||
ty::ty_trait(..) => {
|
||||
@ -267,12 +277,18 @@ impl<'a, 'b> Reflector<'a, 'b> {
|
||||
special_idents::unnamed_field.name;
|
||||
}
|
||||
|
||||
// This and the type_is_sized check on individual field types are
|
||||
// because we cannot reflect unsized types (see note above). We
|
||||
// just pretend the unsized field does not exist and print nothing.
|
||||
// This is sub-optimal.
|
||||
let len = fields.len();
|
||||
|
||||
let extra = (vec!(
|
||||
self.c_slice(
|
||||
token::intern_and_get_ident(ty_to_string(tcx,
|
||||
t).as_slice())),
|
||||
self.c_bool(named_fields),
|
||||
self.c_uint(fields.len())
|
||||
self.c_uint(len)
|
||||
)).append(self.c_size_and_align(t).as_slice());
|
||||
self.bracketed("class", extra.as_slice(), |this| {
|
||||
for (i, field) in fields.iter().enumerate() {
|
||||
|
@ -25,7 +25,7 @@ use middle::trans::datum::*;
|
||||
use middle::trans::expr::{Dest, Ignore, SaveIn};
|
||||
use middle::trans::expr;
|
||||
use middle::trans::glue;
|
||||
use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
|
||||
use middle::trans::machine::{nonzero_llsize_of, llsize_of_alloc};
|
||||
use middle::trans::type_::Type;
|
||||
use middle::trans::type_of;
|
||||
use middle::ty;
|
||||
@ -34,14 +34,14 @@ use util::ppaux::ty_to_string;
|
||||
use syntax::ast;
|
||||
use syntax::parse::token::InternedString;
|
||||
|
||||
pub fn get_fill(bcx: &Block, vptr: ValueRef) -> ValueRef {
|
||||
let _icx = push_ctxt("tvec::get_fill");
|
||||
Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
|
||||
fn get_len(bcx: &Block, vptr: ValueRef) -> ValueRef {
|
||||
let _icx = push_ctxt("tvec::get_lenl");
|
||||
Load(bcx, expr::get_len(bcx, vptr))
|
||||
}
|
||||
|
||||
pub fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
|
||||
fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
|
||||
let _icx = push_ctxt("tvec::get_dataptr");
|
||||
GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
|
||||
Load(bcx, expr::get_dataptr(bcx, vptr))
|
||||
}
|
||||
|
||||
pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
|
||||
@ -56,13 +56,24 @@ pub fn make_drop_glue_unboxed<'a>(
|
||||
vptr: ValueRef,
|
||||
unit_ty: ty::t)
|
||||
-> &'a Block<'a> {
|
||||
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
|
||||
let tcx = bcx.tcx();
|
||||
if ty::type_needs_drop(tcx, unit_ty) {
|
||||
let fill = get_fill(bcx, vptr);
|
||||
let not_null = IsNotNull(bcx, vptr);
|
||||
with_cond(bcx, not_null, |bcx| {
|
||||
let tcx = bcx.tcx();
|
||||
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
|
||||
|
||||
let len = get_len(bcx, vptr);
|
||||
let dataptr = get_dataptr(bcx, vptr);
|
||||
iter_vec_raw(bcx, dataptr, unit_ty, fill, glue::drop_ty)
|
||||
} else { bcx }
|
||||
let bcx = if ty::type_needs_drop(tcx, unit_ty) {
|
||||
iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty)
|
||||
} else {
|
||||
bcx
|
||||
};
|
||||
|
||||
let not_null = IsNotNull(bcx, dataptr);
|
||||
with_cond(bcx, not_null, |bcx| {
|
||||
glue::trans_exchange_free(bcx, dataptr, 0, 8)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub struct VecTypes {
|
||||
@ -85,8 +96,7 @@ impl VecTypes {
|
||||
|
||||
pub fn trans_fixed_vstore<'a>(
|
||||
bcx: &'a Block<'a>,
|
||||
vstore_expr: &ast::Expr,
|
||||
content_expr: &ast::Expr,
|
||||
expr: &ast::Expr,
|
||||
dest: expr::Dest)
|
||||
-> &'a Block<'a> {
|
||||
//!
|
||||
@ -96,50 +106,53 @@ pub fn trans_fixed_vstore<'a>(
|
||||
// to store the array of the suitable size, so all we have to do is
|
||||
// generate the content.
|
||||
|
||||
debug!("trans_fixed_vstore(vstore_expr={}, dest={:?})",
|
||||
bcx.expr_to_string(vstore_expr), dest.to_string(bcx.ccx()));
|
||||
debug!("trans_fixed_vstore(expr={}, dest={:?})",
|
||||
bcx.expr_to_string(expr), dest.to_string(bcx.ccx()));
|
||||
|
||||
let vt = vec_types_from_expr(bcx, vstore_expr);
|
||||
let vt = vec_types_from_expr(bcx, expr);
|
||||
|
||||
return match dest {
|
||||
Ignore => write_content(bcx, &vt, vstore_expr, content_expr, dest),
|
||||
Ignore => write_content(bcx, &vt, expr, expr, dest),
|
||||
SaveIn(lldest) => {
|
||||
// lldest will have type *[T x N], but we want the type *T,
|
||||
// so use GEP to convert:
|
||||
let lldest = GEPi(bcx, lldest, [0, 0]);
|
||||
write_content(bcx, &vt, vstore_expr, content_expr, SaveIn(lldest))
|
||||
write_content(bcx, &vt, expr, expr, SaveIn(lldest))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn trans_slice_vstore<'a>(
|
||||
bcx: &'a Block<'a>,
|
||||
vstore_expr: &ast::Expr,
|
||||
content_expr: &ast::Expr,
|
||||
dest: expr::Dest)
|
||||
-> &'a Block<'a> {
|
||||
pub fn trans_slice_vec<'a>(bcx: &'a Block<'a>,
|
||||
slice_expr: &ast::Expr,
|
||||
content_expr: &ast::Expr)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
/*!
|
||||
* &[...] allocates memory on the stack and writes the values into it,
|
||||
* returning a slice (pair of ptr, len). &"..." is similar except that
|
||||
* the memory can be statically allocated.
|
||||
* returning the vector (the caller must make the reference). "..." is
|
||||
* similar except that the memory can be statically allocated and we return
|
||||
* a reference (strings are always by-ref).
|
||||
*/
|
||||
|
||||
let fcx = bcx.fcx;
|
||||
let ccx = fcx.ccx;
|
||||
let mut bcx = bcx;
|
||||
|
||||
debug!("trans_slice_vstore(vstore_expr={}, dest={})",
|
||||
bcx.expr_to_string(vstore_expr), dest.to_string(ccx));
|
||||
debug!("trans_slice_vec(slice_expr={})",
|
||||
bcx.expr_to_string(slice_expr));
|
||||
|
||||
// Handle the &"..." case:
|
||||
let vec_ty = node_id_type(bcx, slice_expr.id);
|
||||
|
||||
// Handle the "..." case (returns a slice since strings are always unsized):
|
||||
match content_expr.node {
|
||||
ast::ExprLit(lit) => {
|
||||
match lit.node {
|
||||
ast::LitStr(ref s, _) => {
|
||||
return trans_lit_str(bcx,
|
||||
content_expr,
|
||||
s.clone(),
|
||||
dest)
|
||||
let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
|
||||
bcx = trans_lit_str(bcx,
|
||||
content_expr,
|
||||
s.clone(),
|
||||
SaveIn(scratch.val));
|
||||
return DatumBlock::new(bcx, scratch.to_expr_datum());
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -148,46 +161,39 @@ pub fn trans_slice_vstore<'a>(
|
||||
}
|
||||
|
||||
// Handle the &[...] case:
|
||||
let vt = vec_types_from_expr(bcx, vstore_expr);
|
||||
let vt = vec_types_from_expr(bcx, content_expr);
|
||||
let count = elements_required(bcx, content_expr);
|
||||
debug!("vt={}, count={:?}", vt.to_string(ccx), count);
|
||||
|
||||
debug!(" vt={}, count={:?}", vt.to_string(ccx), count);
|
||||
let llcount = C_uint(ccx, count);
|
||||
let llfixed;
|
||||
if count == 0 {
|
||||
|
||||
let fixed_ty = ty::mk_vec(bcx.tcx(),
|
||||
vt.unit_ty,
|
||||
Some(count));
|
||||
let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to();
|
||||
|
||||
let llfixed = if count == 0 {
|
||||
// Just create a zero-sized alloca to preserve
|
||||
// the non-null invariant of the inner slice ptr
|
||||
llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
|
||||
let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
|
||||
BitCast(bcx, llfixed, llfixed_ty)
|
||||
} else {
|
||||
// Make a fixed-length backing array and allocate it on the stack.
|
||||
llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
|
||||
let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
|
||||
|
||||
// Arrange for the backing array to be cleaned up.
|
||||
let fixed_ty = ty::mk_vec(bcx.tcx(),
|
||||
ty::mt {ty: vt.unit_ty,
|
||||
mutbl: ast::MutMutable},
|
||||
Some(count));
|
||||
let llfixed_ty = type_of::type_of(bcx.ccx(), fixed_ty).ptr_to();
|
||||
let llfixed_casted = BitCast(bcx, llfixed, llfixed_ty);
|
||||
let cleanup_scope = cleanup::temporary_scope(bcx.tcx(), content_expr.id);
|
||||
fcx.schedule_lifetime_end(cleanup_scope, llfixed_casted);
|
||||
fcx.schedule_drop_mem(cleanup_scope, llfixed_casted, fixed_ty);
|
||||
|
||||
// Generate the content into the backing array.
|
||||
bcx = write_content(bcx, &vt, vstore_expr,
|
||||
bcx = write_content(bcx, &vt, slice_expr,
|
||||
content_expr, SaveIn(llfixed));
|
||||
}
|
||||
|
||||
// Finally, create the slice pair itself.
|
||||
match dest {
|
||||
Ignore => {}
|
||||
SaveIn(lldest) => {
|
||||
Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
|
||||
Store(bcx, llcount, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
|
||||
}
|
||||
}
|
||||
llfixed_casted
|
||||
};
|
||||
|
||||
return bcx;
|
||||
immediate_rvalue_bcx(bcx, llfixed, vec_ty).to_expr_datumblock()
|
||||
}
|
||||
|
||||
pub fn trans_lit_str<'a>(
|
||||
@ -198,7 +204,7 @@ pub fn trans_lit_str<'a>(
|
||||
-> &'a Block<'a> {
|
||||
/*!
|
||||
* Literal strings translate to slices into static memory. This is
|
||||
* different from trans_slice_vstore() above because it does need to copy
|
||||
* different from trans_slice_vstore() above because it doesn't need to copy
|
||||
* the content anywhere.
|
||||
*/
|
||||
|
||||
@ -214,27 +220,24 @@ pub fn trans_lit_str<'a>(
|
||||
let llbytes = C_uint(bcx.ccx(), bytes);
|
||||
let llcstr = C_cstr(bcx.ccx(), str_lit, false);
|
||||
let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref());
|
||||
Store(bcx, llcstr,
|
||||
GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
|
||||
Store(bcx, llbytes,
|
||||
GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
|
||||
Store(bcx, llcstr, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
|
||||
Store(bcx, llbytes, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
|
||||
bcx
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
|
||||
vstore_expr: &ast::Expr,
|
||||
content_expr: &ast::Expr)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
pub fn trans_uniq_vec<'a>(bcx: &'a Block<'a>,
|
||||
uniq_expr: &ast::Expr,
|
||||
content_expr: &ast::Expr)
|
||||
-> DatumBlock<'a, Expr> {
|
||||
/*!
|
||||
* ~[...] and "...".to_string() allocate boxes in the exchange heap and write
|
||||
* Box<[...]> and "...".to_string() allocate boxes in the exchange heap and write
|
||||
* the array elements into them.
|
||||
*/
|
||||
|
||||
debug!("trans_uniq_vstore(vstore_expr={})", bcx.expr_to_string(vstore_expr));
|
||||
debug!("trans_uniq_vec(uniq_expr={})", bcx.expr_to_string(uniq_expr));
|
||||
let fcx = bcx.fcx;
|
||||
let ccx = fcx.ccx;
|
||||
|
||||
@ -267,45 +270,50 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let vec_ty = node_id_type(bcx, vstore_expr.id);
|
||||
let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
|
||||
let vt = vec_types_from_expr(bcx, content_expr);
|
||||
let count = elements_required(bcx, content_expr);
|
||||
debug!(" vt={}, count={:?}", vt.to_string(ccx), count);
|
||||
let vec_ty = node_id_type(bcx, uniq_expr.id);
|
||||
|
||||
let llunitty = type_of::type_of(ccx, vt.unit_ty);
|
||||
let unit_sz = nonzero_llsize_of(ccx, llunitty);
|
||||
|
||||
let fill = Mul(bcx, C_uint(ccx, count), unit_sz);
|
||||
let alloc = if count < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
|
||||
else { fill };
|
||||
|
||||
let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
|
||||
|
||||
// ~[T] is not going to be changed to support alignment, since it's obsolete.
|
||||
let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty));
|
||||
let llcount = if count < 4u {
|
||||
C_int(ccx, 4)
|
||||
} else {
|
||||
C_uint(ccx, count)
|
||||
};
|
||||
let alloc = Mul(bcx, llcount, unit_sz);
|
||||
let llty_ptr = type_of::type_of(ccx, vt.unit_ty).ptr_to();
|
||||
let align = C_uint(ccx, 8);
|
||||
let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align);
|
||||
Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
|
||||
Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc]));
|
||||
let Result { bcx: bcx, val: dataptr } = malloc_raw_dyn(bcx,
|
||||
llty_ptr,
|
||||
vec_ty,
|
||||
alloc,
|
||||
align);
|
||||
|
||||
// Create a temporary scope lest execution should fail while
|
||||
// constructing the vector.
|
||||
let temp_scope = fcx.push_custom_cleanup_scope();
|
||||
|
||||
// FIXME: #13994: the old `Box<[T]> will not support sized deallocation, this is a placeholder
|
||||
let content_ty = vt.unit_ty;
|
||||
// FIXME: #13994: the old `Box<[T]> will not support sized deallocation,
|
||||
// this is a placeholder
|
||||
fcx.schedule_free_value(cleanup::CustomScope(temp_scope),
|
||||
val, cleanup::HeapExchange, content_ty);
|
||||
dataptr, cleanup::HeapExchange, vt.unit_ty);
|
||||
|
||||
let dataptr = get_dataptr(bcx, val);
|
||||
debug!(" alloc_uniq_vec() returned dataptr={}, len={}",
|
||||
bcx.val_to_string(dataptr), count);
|
||||
|
||||
debug!("alloc_uniq_vec() returned val={}, dataptr={}",
|
||||
bcx.val_to_string(val), bcx.val_to_string(dataptr));
|
||||
|
||||
let bcx = write_content(bcx, &vt, vstore_expr,
|
||||
content_expr, SaveIn(dataptr));
|
||||
let bcx = write_content(bcx, &vt, uniq_expr,
|
||||
content_expr, SaveIn(dataptr));
|
||||
|
||||
fcx.pop_custom_cleanup_scope(temp_scope);
|
||||
|
||||
immediate_rvalue_bcx(bcx, val, vec_ty).to_expr_datumblock()
|
||||
if ty::type_is_sized(bcx.tcx(), vec_ty) {
|
||||
immediate_rvalue_bcx(bcx, dataptr, vec_ty).to_expr_datumblock()
|
||||
} else {
|
||||
let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
|
||||
Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
|
||||
Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
|
||||
DatumBlock::new(bcx, scratch.to_expr_datum())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_content<'a>(
|
||||
@ -451,21 +459,27 @@ pub fn elements_required(bcx: &Block, content_expr: &ast::Expr) -> uint {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_fixed_base_and_byte_len(bcx: &Block,
|
||||
llval: ValueRef,
|
||||
unit_ty: ty::t,
|
||||
vec_length: uint)
|
||||
-> (ValueRef, ValueRef) {
|
||||
pub fn get_fixed_base_and_len(bcx: &Block,
|
||||
llval: ValueRef,
|
||||
vec_length: uint)
|
||||
-> (ValueRef, ValueRef) {
|
||||
/*!
|
||||
* Converts a fixed-length vector into the slice pair.
|
||||
* The vector should be stored in `llval` which should be by ref.
|
||||
*/
|
||||
|
||||
let ccx = bcx.ccx();
|
||||
let vt = vec_types(bcx, unit_ty);
|
||||
|
||||
let base = GEPi(bcx, llval, [0u, 0u]);
|
||||
let len = Mul(bcx, C_uint(ccx, vec_length), vt.llunit_size);
|
||||
let base = expr::get_dataptr(bcx, llval);
|
||||
let len = C_uint(ccx, vec_length);
|
||||
(base, len)
|
||||
}
|
||||
|
||||
fn get_slice_base_and_len(bcx: &Block,
|
||||
llval: ValueRef)
|
||||
-> (ValueRef, ValueRef) {
|
||||
let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
|
||||
let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
|
||||
(base, len)
|
||||
}
|
||||
|
||||
@ -484,27 +498,20 @@ pub fn get_base_and_len(bcx: &Block,
|
||||
let ccx = bcx.ccx();
|
||||
|
||||
match ty::get(vec_ty).sty {
|
||||
ty::ty_vec(_, Some(n)) => {
|
||||
let base = GEPi(bcx, llval, [0u, 0u]);
|
||||
(base, C_uint(ccx, n))
|
||||
}
|
||||
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => {
|
||||
assert!(!type_is_immediate(bcx.ccx(), vec_ty));
|
||||
let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base]));
|
||||
let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
|
||||
(base, count)
|
||||
}
|
||||
_ => ccx.sess().bug("unexpected type (ty_rptr) in get_base_and_len"),
|
||||
ty::ty_vec(_, Some(n)) => get_fixed_base_and_len(bcx, llval, n),
|
||||
ty::ty_open(ty) => match ty::get(ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval),
|
||||
_ => ccx.sess().bug("unexpected type in get_base_and_len")
|
||||
},
|
||||
ty::ty_uniq(t) => match ty::get(t).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => {
|
||||
assert!(type_is_immediate(bcx.ccx(), vec_ty));
|
||||
let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
|
||||
let body = Load(bcx, llval);
|
||||
(get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size))
|
||||
|
||||
// Only used for pattern matching.
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => get_slice_base_and_len(bcx, llval),
|
||||
ty::ty_vec(_, Some(n)) => {
|
||||
let base = GEPi(bcx, Load(bcx, llval), [0u, 0u]);
|
||||
(base, C_uint(ccx, n))
|
||||
}
|
||||
_ => ccx.sess().bug("unexpected type (ty_uniq) in get_base_and_len"),
|
||||
_ => ccx.sess().bug("unexpected type in get_base_and_len"),
|
||||
},
|
||||
_ => ccx.sess().bug("unexpected type in get_base_and_len"),
|
||||
}
|
||||
@ -576,13 +583,15 @@ pub fn iter_vec_raw<'r,
|
||||
bcx: &'b Block<'b>,
|
||||
data_ptr: ValueRef,
|
||||
unit_ty: ty::t,
|
||||
fill: ValueRef,
|
||||
len: ValueRef,
|
||||
f: iter_vec_block<'r,'b>)
|
||||
-> &'b Block<'b> {
|
||||
let _icx = push_ctxt("tvec::iter_vec_raw");
|
||||
let fcx = bcx.fcx;
|
||||
|
||||
let vt = vec_types(bcx, unit_ty);
|
||||
let fill = Mul(bcx, len, vt.llunit_size);
|
||||
|
||||
if vt.llunit_alloc_size == 0 {
|
||||
// Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
|
||||
iter_vec_loop(bcx, data_ptr, &vt, fill, f)
|
||||
|
@ -215,7 +215,7 @@ impl Type {
|
||||
|
||||
pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
|
||||
Type::struct_(ccx,
|
||||
[Type::int(ccx), Type::int(ccx), Type::array(ty, 0)],
|
||||
[Type::array(ty, 0), Type::int(ccx)],
|
||||
false)
|
||||
}
|
||||
|
||||
@ -231,9 +231,16 @@ impl Type {
|
||||
], false)
|
||||
}
|
||||
|
||||
pub fn vtable_ptr(ccx: &CrateContext) -> Type {
|
||||
Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
|
||||
}
|
||||
|
||||
pub fn opaque_trait(ccx: &CrateContext) -> Type {
|
||||
let vtable = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to();
|
||||
Type::struct_(ccx, [vtable, Type::i8p(ccx)], false)
|
||||
Type::struct_(ccx, [Type::opaque_trait_data(ccx).ptr_to(), Type::vtable_ptr(ccx)], false)
|
||||
}
|
||||
|
||||
pub fn opaque_trait_data(ccx: &CrateContext) -> Type {
|
||||
Type::i8(ccx)
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> TypeKind {
|
||||
|
@ -14,7 +14,9 @@ use middle::subst;
|
||||
use middle::trans::adt;
|
||||
use middle::trans::common::*;
|
||||
use middle::trans::foreign;
|
||||
use middle::trans::machine;
|
||||
use middle::ty;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use middle::trans::type_::Type;
|
||||
@ -160,6 +162,11 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
}
|
||||
|
||||
let llsizingty = match ty::get(t).sty {
|
||||
_ if !ty::lltype_is_sized(cx.tcx(), t) => {
|
||||
cx.sess().bug(format!("trying to take the sizing type of {}, an unsized type",
|
||||
ppaux::ty_to_string(cx.tcx(), t)).as_slice())
|
||||
}
|
||||
|
||||
ty::ty_nil | ty::ty_bot => Type::nil(cx),
|
||||
ty::ty_bool => Type::bool(cx),
|
||||
ty::ty_char => Type::char(cx),
|
||||
@ -169,32 +176,24 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
|
||||
ty::ty_box(..) |
|
||||
ty::ty_ptr(..) => Type::i8p(cx),
|
||||
ty::ty_uniq(ty) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_trait(..) => Type::opaque_trait(cx),
|
||||
_ => Type::i8p(cx),
|
||||
}
|
||||
}
|
||||
ty::ty_rptr(_, mt) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => {
|
||||
Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
|
||||
}
|
||||
ty::ty_trait(..) => Type::opaque_trait(cx),
|
||||
_ => Type::i8p(cx),
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
|
||||
if ty::type_is_sized(cx.tcx(), ty) {
|
||||
Type::i8p(cx)
|
||||
} else {
|
||||
Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_bare_fn(..) => Type::i8p(cx),
|
||||
ty::ty_closure(..) => Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false),
|
||||
|
||||
ty::ty_vec(mt, Some(size)) => {
|
||||
Type::array(&sizing_type_of(cx, mt.ty), size as u64)
|
||||
ty::ty_vec(ty, Some(size)) => {
|
||||
Type::array(&sizing_type_of(cx, ty), size as u64)
|
||||
}
|
||||
|
||||
ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_unboxed_closure(..) => {
|
||||
let repr = adt::represent_type(cx, t);
|
||||
adt::sizing_type_of(cx, &*repr)
|
||||
adt::sizing_type_of(cx, &*repr, false)
|
||||
}
|
||||
|
||||
ty::ty_struct(..) => {
|
||||
@ -204,15 +203,19 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
Type::vector(&type_of(cx, et), n as u64)
|
||||
} else {
|
||||
let repr = adt::represent_type(cx, t);
|
||||
adt::sizing_type_of(cx, &*repr)
|
||||
adt::sizing_type_of(cx, &*repr, false)
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_infer(..) | ty::ty_param(..) |
|
||||
ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {
|
||||
cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()",
|
||||
ty::get(t).sty).as_slice())
|
||||
ty::ty_open(_) => {
|
||||
Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
|
||||
}
|
||||
|
||||
ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
|
||||
cx.sess().bug(format!("fictitious type {} in sizing_type_of()",
|
||||
ppaux::ty_to_string(cx.tcx(), t)).as_slice())
|
||||
}
|
||||
ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => fail!("unreachable")
|
||||
};
|
||||
|
||||
cx.llsizingtypes.borrow_mut().insert(t, llsizingty);
|
||||
@ -229,13 +232,30 @@ pub fn arg_type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
|
||||
// NB: If you update this, be sure to update `sizing_type_of()` as well.
|
||||
pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
fn type_of_unsize_info(cx: &CrateContext, t: ty::t) -> Type {
|
||||
// It is possible to end up here with a sized type. This happens with a
|
||||
// struct which might be unsized, but is monomorphised to a sized type.
|
||||
// In this case we'll fake a fat pointer with no unsize info (we use 0).
|
||||
// However, its still a fat pointer, so we need some type use.
|
||||
if ty::type_is_sized(cx.tcx(), t) {
|
||||
return Type::i8p(cx);
|
||||
}
|
||||
|
||||
match ty::get(ty::unsized_part_of_type(cx.tcx(), t)).sty {
|
||||
ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyU),
|
||||
ty::ty_trait(_) => Type::vtable_ptr(cx),
|
||||
_ => fail!("Unexpected type returned from unsized_part_of_type : {}",
|
||||
t.repr(cx.tcx()))
|
||||
}
|
||||
}
|
||||
|
||||
// Check the cache.
|
||||
match cx.lltypes.borrow().find(&t) {
|
||||
Some(&llty) => return llty,
|
||||
None => ()
|
||||
}
|
||||
|
||||
debug!("type_of {} {:?}", t.repr(cx.tcx()), t);
|
||||
debug!("type_of {} {:?}", t.repr(cx.tcx()), ty::get(t).sty);
|
||||
|
||||
// Replace any typedef'd types with their equivalent non-typedef
|
||||
// type. This ensures that all LLVM nominal types that contain
|
||||
@ -283,34 +303,36 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
ty::ty_box(typ) => {
|
||||
Type::at_box(cx, type_of(cx, typ)).ptr_to()
|
||||
}
|
||||
ty::ty_uniq(typ) => {
|
||||
match ty::get(typ).sty {
|
||||
ty::ty_vec(mt, None) => Type::vec(cx, &type_of(cx, mt.ty)).ptr_to(),
|
||||
ty::ty_str => Type::vec(cx, &Type::i8(cx)).ptr_to(),
|
||||
ty::ty_trait(..) => Type::opaque_trait(cx),
|
||||
_ => type_of(cx, typ).ptr_to(),
|
||||
}
|
||||
}
|
||||
ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(),
|
||||
ty::ty_rptr(_, ref mt) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(mt, None) => {
|
||||
let p_ty = type_of(cx, mt.ty).ptr_to();
|
||||
let u_ty = Type::uint_from_ty(cx, ast::TyU);
|
||||
Type::struct_(cx, [p_ty, u_ty], false)
|
||||
}
|
||||
|
||||
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_str => {
|
||||
// This means we get a nicer name in the output
|
||||
// This means we get a nicer name in the output (str is always
|
||||
// unsized).
|
||||
cx.tn.find_type("str_slice").unwrap()
|
||||
}
|
||||
ty::ty_trait(..) => Type::opaque_trait(cx),
|
||||
_ => type_of(cx, mt.ty).ptr_to(),
|
||||
_ if !ty::type_is_sized(cx.tcx(), ty) => {
|
||||
let p_ty = type_of(cx, ty).ptr_to();
|
||||
Type::struct_(cx, [p_ty, type_of_unsize_info(cx, ty)], false)
|
||||
}
|
||||
_ => type_of(cx, ty).ptr_to(),
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_vec(ref mt, Some(n)) => {
|
||||
Type::array(&type_of(cx, mt.ty), n as u64)
|
||||
ty::ty_vec(ty, Some(n)) => {
|
||||
Type::array(&type_of(cx, ty), n as u64)
|
||||
}
|
||||
ty::ty_vec(ty, None) => {
|
||||
type_of(cx, ty)
|
||||
}
|
||||
|
||||
ty::ty_trait(..) => {
|
||||
Type::opaque_trait_data(cx)
|
||||
}
|
||||
|
||||
ty::ty_str => Type::i8(cx),
|
||||
|
||||
ty::ty_bare_fn(_) => {
|
||||
type_of_fn_from_ty(cx, t).ptr_to()
|
||||
@ -339,12 +361,27 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_vec(_, None) => cx.sess().bug("type_of with unsized ty_vec"),
|
||||
ty::ty_str => cx.sess().bug("type_of with unsized (bare) ty_str"),
|
||||
ty::ty_trait(..) => cx.sess().bug("type_of with unsized ty_trait"),
|
||||
ty::ty_open(t) => match ty::get(t).sty {
|
||||
ty::ty_struct(..) => {
|
||||
let p_ty = type_of(cx, t).ptr_to();
|
||||
Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false)
|
||||
}
|
||||
ty::ty_vec(ty, None) => {
|
||||
let p_ty = type_of(cx, ty).ptr_to();
|
||||
Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false)
|
||||
}
|
||||
ty::ty_str => {
|
||||
let p_ty = Type::i8p(cx);
|
||||
Type::struct_(cx, [p_ty, type_of_unsize_info(cx, t)], false)
|
||||
}
|
||||
ty::ty_trait(..) => Type::opaque_trait(cx),
|
||||
_ => cx.sess().bug(format!("ty_open with sized type: {}",
|
||||
ppaux::ty_to_string(cx.tcx(), t)).as_slice())
|
||||
},
|
||||
|
||||
ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
|
||||
ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
|
||||
ty::ty_err(..) => cx.sess().bug("type_of with ty_err")
|
||||
ty::ty_err(..) => cx.sess().bug("type_of with ty_err"),
|
||||
};
|
||||
|
||||
debug!("--> mapped t={} {:?} to llty={}",
|
||||
@ -367,6 +404,11 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
|
||||
return llty;
|
||||
}
|
||||
|
||||
pub fn align_of(cx: &CrateContext, t: ty::t) -> u64 {
|
||||
let llty = sizing_type_of(cx, t);
|
||||
machine::llalign_of_min(cx, llty)
|
||||
}
|
||||
|
||||
// Want refinements! (Or case classes, I guess
|
||||
pub enum named_ty {
|
||||
a_struct,
|
||||
|
@ -263,37 +263,138 @@ pub enum Variance {
|
||||
#[deriving(Clone)]
|
||||
pub enum AutoAdjustment {
|
||||
AutoAddEnv(ty::TraitStore),
|
||||
AutoDerefRef(AutoDerefRef),
|
||||
AutoObject(ty::TraitStore,
|
||||
ty::BuiltinBounds,
|
||||
ast::DefId, /* Trait ID */
|
||||
subst::Substs /* Trait substitutions */)
|
||||
AutoDerefRef(AutoDerefRef)
|
||||
}
|
||||
|
||||
#[deriving(Clone, Decodable, Encodable)]
|
||||
#[deriving(Clone, PartialEq)]
|
||||
pub enum UnsizeKind {
|
||||
// [T, ..n] -> [T], the uint field is n.
|
||||
UnsizeLength(uint),
|
||||
// An unsize coercion applied to the tail field of a struct.
|
||||
// The uint is the index of the type parameter which is unsized.
|
||||
UnsizeStruct(Box<UnsizeKind>, uint),
|
||||
UnsizeVtable(ty::BuiltinBounds,
|
||||
ast::DefId, /* Trait ID */
|
||||
subst::Substs /* Trait substitutions */)
|
||||
}
|
||||
|
||||
#[deriving(Clone)]
|
||||
pub struct AutoDerefRef {
|
||||
pub autoderefs: uint,
|
||||
pub autoref: Option<AutoRef>
|
||||
}
|
||||
|
||||
#[deriving(Clone, Decodable, Encodable, PartialEq, Show)]
|
||||
#[deriving(Clone, PartialEq)]
|
||||
pub enum AutoRef {
|
||||
/// Convert from T to &T
|
||||
AutoPtr(Region, ast::Mutability),
|
||||
/// The third field allows us to wrap other AutoRef adjustments.
|
||||
AutoPtr(Region, ast::Mutability, Option<Box<AutoRef>>),
|
||||
|
||||
/// Convert from ~[]/&[] to &[] or str
|
||||
AutoBorrowVec(Region, ast::Mutability),
|
||||
/// Convert [T, ..n] to [T] (or similar, depending on the kind)
|
||||
AutoUnsize(UnsizeKind),
|
||||
|
||||
/// Convert from ~[]/&[] to &&[] or str
|
||||
AutoBorrowVecRef(Region, ast::Mutability),
|
||||
/// Convert Box<[T, ..n]> to Box<[T]> or something similar in a Box.
|
||||
/// With DST and Box a library type, this should be replaced by UnsizeStruct.
|
||||
AutoUnsizeUniq(UnsizeKind),
|
||||
|
||||
/// Convert from T to *T
|
||||
/// Value to thin pointer
|
||||
AutoUnsafe(ast::Mutability),
|
||||
|
||||
/// Convert from Box<Trait>/&Trait to &Trait
|
||||
AutoBorrowObj(Region, ast::Mutability),
|
||||
}
|
||||
|
||||
// Ugly little helper function. The first bool in the returned tuple is true if
|
||||
// there is an 'unsize to trait object' adjustment at the bottom of the
|
||||
// adjustment. If that is surrounded by an AutoPtr, then we also return the
|
||||
// region of the AutoPtr (in the third argument). The second bool is true if the
|
||||
// adjustment is unique.
|
||||
fn autoref_object_region(autoref: &AutoRef) -> (bool, bool, Option<Region>) {
|
||||
fn unsize_kind_is_object(k: &UnsizeKind) -> bool {
|
||||
match k {
|
||||
&UnsizeVtable(..) => true,
|
||||
&UnsizeStruct(box ref k, _) => unsize_kind_is_object(k),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
match autoref {
|
||||
&AutoUnsize(ref k) => (unsize_kind_is_object(k), false, None),
|
||||
&AutoUnsizeUniq(ref k) => (unsize_kind_is_object(k), true, None),
|
||||
&AutoPtr(adj_r, _, Some(box ref autoref)) => {
|
||||
let (b, u, r) = autoref_object_region(autoref);
|
||||
if r.is_some() || u {
|
||||
(b, u, r)
|
||||
} else {
|
||||
(b, u, Some(adj_r))
|
||||
}
|
||||
}
|
||||
_ => (false, false, None)
|
||||
}
|
||||
}
|
||||
|
||||
// If the adjustment introduces a borrowed reference to a trait object, then
|
||||
// returns the region of the borrowed reference.
|
||||
pub fn adjusted_object_region(adj: &AutoAdjustment) -> Option<Region> {
|
||||
match adj {
|
||||
&AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
|
||||
let (b, _, r) = autoref_object_region(autoref);
|
||||
if b {
|
||||
r
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if there is a trait cast at the bottom of the adjustment.
|
||||
pub fn adjust_is_object(adj: &AutoAdjustment) -> bool {
|
||||
match adj {
|
||||
&AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
|
||||
let (b, _, _) = autoref_object_region(autoref);
|
||||
b
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
// If possible, returns the type expected from the given adjustment. This is not
|
||||
// possible if the adjustment depends on the type of the adjusted expression.
|
||||
pub fn type_of_adjust(cx: &ctxt, adj: &AutoAdjustment) -> Option<t> {
|
||||
fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option<t> {
|
||||
match autoref {
|
||||
&AutoUnsize(ref k) => match k {
|
||||
&UnsizeVtable(bounds, def_id, ref substs) => {
|
||||
Some(mk_trait(cx, def_id, substs.clone(), bounds))
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
&AutoUnsizeUniq(ref k) => match k {
|
||||
&UnsizeVtable(bounds, def_id, ref substs) => {
|
||||
Some(mk_uniq(cx, mk_trait(cx, def_id, substs.clone(), bounds)))
|
||||
}
|
||||
_ => None
|
||||
},
|
||||
&AutoPtr(r, m, Some(box ref autoref)) => {
|
||||
match type_of_autoref(cx, autoref) {
|
||||
Some(t) => Some(mk_rptr(cx, r, mt {mutbl: m, ty: t})),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
match adj {
|
||||
&AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), ..}) => {
|
||||
type_of_autoref(cx, autoref)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// A restriction that certain types must be the same size. The use of
|
||||
/// `transmute` gives rise to these restrictions.
|
||||
pub struct TransmuteRestriction {
|
||||
@ -303,6 +404,8 @@ pub struct TransmuteRestriction {
|
||||
pub from: t,
|
||||
/// The type being transmuted to.
|
||||
pub to: t,
|
||||
/// NodeIf of the transmute intrinsic.
|
||||
pub id: ast::NodeId,
|
||||
}
|
||||
|
||||
/// The data structure to keep track of all the information that typechecker
|
||||
@ -802,7 +905,7 @@ pub enum sty {
|
||||
ty_box(t),
|
||||
ty_uniq(t),
|
||||
ty_str,
|
||||
ty_vec(mt, Option<uint>), // Second field is length.
|
||||
ty_vec(t, Option<uint>), // Second field is length.
|
||||
ty_ptr(mt),
|
||||
ty_rptr(Region, mt),
|
||||
ty_bare_fn(BareFnTy),
|
||||
@ -813,6 +916,12 @@ pub enum sty {
|
||||
ty_tup(Vec<t>),
|
||||
|
||||
ty_param(ParamTy), // type parameter
|
||||
ty_open(t), // A deref'ed fat pointer, i.e., a dynamically sized value
|
||||
// and its size. Only ever used in trans. It is not necessary
|
||||
// earlier since we don't need to distinguish a DST with its
|
||||
// size (e.g., in a deref) vs a DST with the size elsewhere (
|
||||
// e.g., in a field).
|
||||
|
||||
ty_infer(InferTy), // something used only during inference/typeck
|
||||
ty_err, // Also only used during inference/typeck, to represent
|
||||
// the type of an erroneous expression (helps cut down
|
||||
@ -1377,10 +1486,10 @@ pub fn mk_t(cx: &ctxt, st: sty) -> t {
|
||||
&ty_trait(box ty::TyTrait { ref substs, .. }) => {
|
||||
flags |= sflags(substs);
|
||||
}
|
||||
&ty_box(tt) | &ty_uniq(tt) => {
|
||||
&ty_box(tt) | &ty_uniq(tt) | &ty_vec(tt, _) | &ty_open(tt) => {
|
||||
flags |= get(tt).flags
|
||||
}
|
||||
&ty_ptr(ref m) | &ty_vec(ref m, _) => {
|
||||
&ty_ptr(ref m) => {
|
||||
flags |= get(m.ty).flags;
|
||||
}
|
||||
&ty_rptr(r, ref m) => {
|
||||
@ -1558,14 +1667,14 @@ pub fn mk_nil_ptr(cx: &ctxt) -> t {
|
||||
mk_ptr(cx, mt {ty: mk_nil(), mutbl: ast::MutImmutable})
|
||||
}
|
||||
|
||||
pub fn mk_vec(cx: &ctxt, tm: mt, sz: Option<uint>) -> t {
|
||||
mk_t(cx, ty_vec(tm, sz))
|
||||
pub fn mk_vec(cx: &ctxt, t: t, sz: Option<uint>) -> t {
|
||||
mk_t(cx, ty_vec(t, sz))
|
||||
}
|
||||
|
||||
pub fn mk_slice(cx: &ctxt, r: Region, tm: mt) -> t {
|
||||
mk_rptr(cx, r,
|
||||
mt {
|
||||
ty: mk_vec(cx, tm, None),
|
||||
ty: mk_vec(cx, tm.ty, None),
|
||||
mutbl: tm.mutbl
|
||||
})
|
||||
}
|
||||
@ -1643,6 +1752,8 @@ pub fn mk_param_from_def(cx: &ctxt, def: &TypeParameterDef) -> t {
|
||||
mk_param(cx, def.space, def.index, def.def_id)
|
||||
}
|
||||
|
||||
pub fn mk_open(cx: &ctxt, t: t) -> t { mk_t(cx, ty_open(t)) }
|
||||
|
||||
pub fn walk_ty(ty: t, f: |t|) {
|
||||
maybe_walk_ty(ty, |t| { f(t); true });
|
||||
}
|
||||
@ -1653,10 +1764,9 @@ pub fn maybe_walk_ty(ty: t, f: |t| -> bool) {
|
||||
}
|
||||
match get(ty).sty {
|
||||
ty_nil | ty_bot | ty_bool | ty_char | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||
ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(..) |
|
||||
ty_err => {}
|
||||
ty_box(ty) | ty_uniq(ty) => maybe_walk_ty(ty, f),
|
||||
ty_ptr(ref tm) | ty_rptr(_, ref tm) | ty_vec(ref tm, _) => {
|
||||
ty_str | ty_infer(_) | ty_param(_) | ty_unboxed_closure(_, _) | ty_err => {}
|
||||
ty_box(ty) | ty_uniq(ty) | ty_vec(ty, _) | ty_open(ty) => maybe_walk_ty(ty, f),
|
||||
ty_ptr(ref tm) | ty_rptr(_, ref tm) => {
|
||||
maybe_walk_ty(tm.ty, f);
|
||||
}
|
||||
ty_enum(_, ref substs) | ty_struct(_, ref substs) |
|
||||
@ -1775,14 +1885,11 @@ pub fn type_is_simd(cx: &ctxt, ty: t) -> bool {
|
||||
|
||||
pub fn sequence_element_type(cx: &ctxt, ty: t) -> t {
|
||||
match get(ty).sty {
|
||||
ty_vec(mt, _) => mt.ty,
|
||||
ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) |
|
||||
ty_box(t) | ty_uniq(t) => match get(t).sty {
|
||||
ty_vec(mt, None) => mt.ty,
|
||||
ty_str => mk_mach_uint(ast::TyU8),
|
||||
_ => cx.sess.bug("sequence_element_type called on non-sequence value"),
|
||||
},
|
||||
_ => cx.sess.bug("sequence_element_type called on non-sequence value"),
|
||||
ty_vec(ty, _) => ty,
|
||||
ty_str => mk_mach_uint(ast::TyU8),
|
||||
ty_open(ty) => sequence_element_type(cx, ty),
|
||||
_ => cx.sess.bug(format!("sequence_element_type called on non-sequence value: {}",
|
||||
ty_to_string(cx, ty)).as_slice()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -1815,12 +1922,7 @@ pub fn type_is_boxed(ty: t) -> bool {
|
||||
|
||||
pub fn type_is_region_ptr(ty: t) -> bool {
|
||||
match get(ty).sty {
|
||||
ty_rptr(_, mt) => match get(mt.ty).sty {
|
||||
// FIXME(nrc, DST) slices weren't regarded as rptrs, so we preserve this
|
||||
// odd behaviour for now. (But ~[] were unique. I have no idea why).
|
||||
ty_vec(_, None) | ty_str | ty_trait(..) => false,
|
||||
_ => true
|
||||
},
|
||||
ty_rptr(..) => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
@ -1842,6 +1944,13 @@ pub fn type_is_unique(ty: t) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_is_fat_ptr(cx: &ctxt, ty: t) -> bool {
|
||||
match get(ty).sty {
|
||||
ty_rptr(_, mt{ty, ..}) | ty_uniq(ty) if !type_is_sized(cx, ty) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
A scalar type is one that denotes an atomic datum, with no sub-components.
|
||||
(A ty_ptr is scalar because it represents a non-managed pointer, so its
|
||||
@ -2233,7 +2342,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
|
||||
// Scalar and unique types are sendable, and durable
|
||||
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
|
||||
ty_bare_fn(_) | ty::ty_char | ty_str => {
|
||||
ty_bare_fn(_) | ty::ty_char => {
|
||||
TC::None
|
||||
}
|
||||
|
||||
@ -2268,10 +2377,15 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
}
|
||||
}
|
||||
|
||||
ty_vec(mt, _) => {
|
||||
tc_mt(cx, mt, cache)
|
||||
ty_vec(t, Some(_)) => {
|
||||
tc_ty(cx, t, cache)
|
||||
}
|
||||
|
||||
ty_vec(t, None) => {
|
||||
tc_ty(cx, t, cache) | TC::Nonsized
|
||||
}
|
||||
ty_str => TC::Nonsized,
|
||||
|
||||
ty_struct(did, ref substs) => {
|
||||
let flds = struct_fields(cx, did, substs);
|
||||
let mut res =
|
||||
@ -2371,7 +2485,7 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
kind_bounds_to_contents(cx,
|
||||
tp_def.bounds.builtin_bounds,
|
||||
tp_def.bounds.trait_bounds.as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
ty_infer(_) => {
|
||||
// This occurs during coherence, but shouldn't occur at other
|
||||
@ -2379,6 +2493,12 @@ pub fn type_contents(cx: &ctxt, ty: t) -> TypeContents {
|
||||
TC::All
|
||||
}
|
||||
|
||||
ty_open(t) => {
|
||||
let result = tc_ty(cx, t, cache);
|
||||
assert!(!result.is_sized(cx))
|
||||
result.unsafe_pointer() | TC::Nonsized
|
||||
}
|
||||
|
||||
ty_err => {
|
||||
cx.sess.bug("asked to compute contents of error type");
|
||||
}
|
||||
@ -2540,7 +2660,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
|
||||
// normal vectors, since they don't necessarily have the
|
||||
// possibility to have length zero.
|
||||
ty_vec(_, Some(0)) => false, // don't need no contents
|
||||
ty_vec(mt, Some(_)) => type_requires(cx, seen, r_ty, mt.ty),
|
||||
ty_vec(ty, Some(_)) => type_requires(cx, seen, r_ty, ty),
|
||||
|
||||
ty_nil |
|
||||
ty_bot |
|
||||
@ -2558,7 +2678,7 @@ pub fn is_instantiable(cx: &ctxt, r_ty: t) -> bool {
|
||||
ty_vec(_, None) => {
|
||||
false
|
||||
}
|
||||
ty_box(typ) | ty_uniq(typ) => {
|
||||
ty_box(typ) | ty_uniq(typ) | ty_open(typ) => {
|
||||
type_requires(cx, seen, r_ty, typ)
|
||||
}
|
||||
ty_rptr(_, ref mt) => {
|
||||
@ -2681,8 +2801,8 @@ pub fn is_type_representable(cx: &ctxt, sp: Span, ty: t) -> Representability {
|
||||
}
|
||||
// Fixed-length vectors.
|
||||
// FIXME(#11924) Behavior undecided for zero-length vectors.
|
||||
ty_vec(mt, Some(_)) => {
|
||||
type_structurally_recursive(cx, sp, seen, mt.ty)
|
||||
ty_vec(ty, Some(_)) => {
|
||||
type_structurally_recursive(cx, sp, seen, ty)
|
||||
}
|
||||
|
||||
// Push struct and enum def-ids onto `seen` before recursing.
|
||||
@ -2801,11 +2921,40 @@ pub fn type_is_machine(ty: t) -> bool {
|
||||
}
|
||||
|
||||
// Is the type's representation size known at compile time?
|
||||
#[allow(dead_code)] // leaving in for DST
|
||||
pub fn type_is_sized(cx: &ctxt, ty: ty::t) -> bool {
|
||||
pub fn type_is_sized(cx: &ctxt, ty: t) -> bool {
|
||||
type_contents(cx, ty).is_sized(cx)
|
||||
}
|
||||
|
||||
pub fn lltype_is_sized(cx: &ctxt, ty: t) -> bool {
|
||||
match get(ty).sty {
|
||||
ty_open(_) => true,
|
||||
_ => type_contents(cx, ty).is_sized(cx)
|
||||
}
|
||||
}
|
||||
|
||||
// Return the smallest part of t which is unsized. Fails if t is sized.
|
||||
// 'Smallest' here means component of the static representation of the type; not
|
||||
// the size of an object at runtime.
|
||||
pub fn unsized_part_of_type(cx: &ctxt, ty: t) -> t {
|
||||
match get(ty).sty {
|
||||
ty_str | ty_trait(..) | ty_vec(..) => ty,
|
||||
ty_struct(_, ref substs) => {
|
||||
// Exactly one of the type parameters must be unsized.
|
||||
for tp in substs.types.get_slice(subst::TypeSpace).iter() {
|
||||
if !type_is_sized(cx, *tp) {
|
||||
return unsized_part_of_type(cx, *tp);
|
||||
}
|
||||
}
|
||||
fail!("Unsized struct type with no unsized type params? {}", ty_to_string(cx, ty));
|
||||
}
|
||||
_ => {
|
||||
assert!(type_is_sized(cx, ty),
|
||||
"unsized_part_of_type failed even though ty is unsized");
|
||||
fail!("called unsized_part_of_type with sized ty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Whether a type is enum like, that is an enum type with only nullary
|
||||
// constructors
|
||||
pub fn type_is_c_like_enum(cx: &ctxt, ty: t) -> bool {
|
||||
@ -2828,33 +2977,57 @@ pub fn type_is_c_like_enum(cx: &ctxt, ty: t) -> bool {
|
||||
// Some types---notably unsafe ptrs---can only be dereferenced explicitly.
|
||||
pub fn deref(t: t, explicit: bool) -> Option<mt> {
|
||||
match get(t).sty {
|
||||
ty_box(typ) | ty_uniq(typ) => match get(typ).sty {
|
||||
// Don't deref ~[] etc., might need to generalise this to all DST.
|
||||
ty_vec(_, None) | ty_str | ty_trait(..) => None,
|
||||
_ => Some(mt {
|
||||
ty: typ,
|
||||
ty_box(ty) | ty_uniq(ty) => {
|
||||
Some(mt {
|
||||
ty: ty,
|
||||
mutbl: ast::MutImmutable,
|
||||
}),
|
||||
},
|
||||
ty_rptr(_, mt) => match get(mt.ty).sty {
|
||||
// Don't deref &[], might need to generalise this to all DST.
|
||||
ty_vec(_, None) | ty_str | ty_trait(..) => None,
|
||||
_ => Some(mt),
|
||||
})
|
||||
},
|
||||
ty_rptr(_, mt) => Some(mt),
|
||||
ty_ptr(mt) if explicit => Some(mt),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the type of t[i]
|
||||
pub fn index(t: t) -> Option<mt> {
|
||||
pub fn deref_or_dont(t: t) -> t {
|
||||
match get(t).sty {
|
||||
ty_vec(mt, Some(_)) => Some(mt),
|
||||
ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) |
|
||||
ty_box(t) | ty_uniq(t) => match get(t).sty {
|
||||
ty_vec(mt, None) => Some(mt),
|
||||
_ => None,
|
||||
ty_box(ty) | ty_uniq(ty) => {
|
||||
ty
|
||||
},
|
||||
ty_rptr(_, mt) | ty_ptr(mt) => mt.ty,
|
||||
_ => t
|
||||
}
|
||||
}
|
||||
|
||||
pub fn close_type(cx: &ctxt, t: t) -> t {
|
||||
match get(t).sty {
|
||||
ty_open(t) => mk_rptr(cx, ReStatic, mt {ty: t, mutbl:ast::MutImmutable}),
|
||||
_ => cx.sess.bug(format!("Trying to close a non-open type {}",
|
||||
ty_to_string(cx, t)).as_slice())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_content(t: t) -> t {
|
||||
match get(t).sty {
|
||||
ty_box(ty) | ty_uniq(ty) => ty,
|
||||
ty_rptr(_, mt) |ty_ptr(mt) => mt.ty,
|
||||
_ => t
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Extract the unsized type in an open type (or just return t if it is not open).
|
||||
pub fn unopen_type(t: t) -> t {
|
||||
match get(t).sty {
|
||||
ty_open(t) => t,
|
||||
_ => t
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the type of t[i]
|
||||
pub fn index(ty: t) -> Option<t> {
|
||||
match get(ty).sty {
|
||||
ty_vec(t, _) => Some(t),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -2862,15 +3035,10 @@ pub fn index(t: t) -> Option<mt> {
|
||||
// Returns the type of elements contained within an 'array-like' type.
|
||||
// This is exactly the same as the above, except it supports strings,
|
||||
// which can't actually be indexed.
|
||||
pub fn array_element_ty(t: t) -> Option<mt> {
|
||||
pub fn array_element_ty(t: t) -> Option<t> {
|
||||
match get(t).sty {
|
||||
ty_vec(mt, Some(_)) => Some(mt),
|
||||
ty_ptr(mt{ty: t, ..}) | ty_rptr(_, mt{ty: t, ..}) |
|
||||
ty_box(t) | ty_uniq(t) => match get(t).sty {
|
||||
ty_vec(mt, None) => Some(mt),
|
||||
ty_str => Some(mt {ty: mk_u8(), mutbl: ast::MutImmutable}),
|
||||
_ => None,
|
||||
},
|
||||
ty_vec(t, _) => Some(t),
|
||||
ty_str => Some(mk_u8()),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
@ -3153,56 +3321,7 @@ pub fn adjust_ty(cx: &ctxt,
|
||||
|
||||
match adj.autoref {
|
||||
None => adjusted_ty,
|
||||
Some(ref autoref) => {
|
||||
match *autoref {
|
||||
AutoPtr(r, m) => {
|
||||
mk_rptr(cx, r, mt {
|
||||
ty: adjusted_ty,
|
||||
mutbl: m
|
||||
})
|
||||
}
|
||||
|
||||
AutoBorrowVec(r, m) => {
|
||||
borrow_vec(cx, span, r, m, adjusted_ty)
|
||||
}
|
||||
|
||||
AutoBorrowVecRef(r, m) => {
|
||||
adjusted_ty = borrow_vec(cx,
|
||||
span,
|
||||
r,
|
||||
m,
|
||||
adjusted_ty);
|
||||
mk_rptr(cx, r, mt {
|
||||
ty: adjusted_ty,
|
||||
mutbl: ast::MutImmutable
|
||||
})
|
||||
}
|
||||
|
||||
AutoUnsafe(m) => {
|
||||
mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m})
|
||||
}
|
||||
|
||||
AutoBorrowObj(r, m) => {
|
||||
borrow_obj(cx, span, r, m, adjusted_ty)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AutoObject(store, bounds, def_id, ref substs) => {
|
||||
|
||||
let tr = mk_trait(cx, def_id, substs.clone(), bounds);
|
||||
match store {
|
||||
UniqTraitStore => {
|
||||
mk_uniq(cx, tr)
|
||||
}
|
||||
RegionTraitStore(r, m) => {
|
||||
mk_rptr(cx, r, mt {
|
||||
ty: tr,
|
||||
mutbl: m
|
||||
})
|
||||
}
|
||||
Some(ref autoref) => adjust_for_autoref(cx, span, adjusted_ty, autoref)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3210,57 +3329,63 @@ pub fn adjust_ty(cx: &ctxt,
|
||||
None => unadjusted_ty
|
||||
};
|
||||
|
||||
fn borrow_vec(cx: &ctxt,
|
||||
span: Span,
|
||||
r: Region,
|
||||
m: ast::Mutability,
|
||||
ty: ty::t) -> ty::t {
|
||||
match get(ty).sty {
|
||||
ty_uniq(t) | ty_ptr(mt{ty: t, ..}) |
|
||||
ty_rptr(_, mt{ty: t, ..}) => match get(t).sty {
|
||||
ty::ty_vec(mt, None) => ty::mk_slice(cx, r, ty::mt {ty: mt.ty, mutbl: m}),
|
||||
ty::ty_str => ty::mk_str_slice(cx, r, m),
|
||||
_ => {
|
||||
cx.sess.span_bug(
|
||||
span,
|
||||
format!("borrow-vec associated with bad sty: {:?}",
|
||||
get(ty).sty).as_slice());
|
||||
}
|
||||
},
|
||||
ty_vec(mt, Some(_)) => ty::mk_slice(cx, r, ty::mt {ty: mt.ty, mutbl: m}),
|
||||
|
||||
ref s => {
|
||||
cx.sess.span_bug(
|
||||
span,
|
||||
format!("borrow-vec associated with bad sty: {:?}",
|
||||
s).as_slice());
|
||||
fn adjust_for_autoref(cx: &ctxt,
|
||||
span: Span,
|
||||
ty: ty::t,
|
||||
autoref: &AutoRef) -> ty::t{
|
||||
match *autoref {
|
||||
AutoPtr(r, m, ref a) => {
|
||||
let adjusted_ty = match a {
|
||||
&Some(box ref a) => adjust_for_autoref(cx, span, ty, a),
|
||||
&None => ty
|
||||
};
|
||||
mk_rptr(cx, r, mt {
|
||||
ty: adjusted_ty,
|
||||
mutbl: m
|
||||
})
|
||||
}
|
||||
|
||||
AutoUnsafe(m) => {
|
||||
mk_ptr(cx, mt {ty: ty, mutbl: m})
|
||||
}
|
||||
|
||||
AutoUnsize(ref k) => unsize_ty(cx, ty, k, span),
|
||||
AutoUnsizeUniq(ref k) => ty::mk_uniq(cx, unsize_ty(cx, ty, k, span)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn borrow_obj(cx: &ctxt, span: Span, r: Region,
|
||||
m: ast::Mutability, ty: ty::t) -> ty::t {
|
||||
match get(ty).sty {
|
||||
ty_uniq(t) | ty_rptr(_, mt{ty: t, ..}) => match get(t).sty {
|
||||
ty_trait(box ty::TyTrait {def_id, ref substs, bounds, .. }) => {
|
||||
mk_rptr(cx, r, mt {
|
||||
ty: ty::mk_trait(cx, def_id, substs.clone(), bounds),
|
||||
mutbl: m
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
cx.sess.span_bug(
|
||||
span,
|
||||
format!("borrow-trait-obj associated with bad sty: {:?}",
|
||||
get(ty).sty).as_slice());
|
||||
}
|
||||
},
|
||||
ref s => {
|
||||
cx.sess.span_bug(
|
||||
span,
|
||||
format!("borrow-trait-obj associated with bad sty: {:?}",
|
||||
s).as_slice());
|
||||
// Take a sized type and a sizing adjustment and produce an unsized version of
|
||||
// the type.
|
||||
pub fn unsize_ty(cx: &ctxt,
|
||||
ty: ty::t,
|
||||
kind: &UnsizeKind,
|
||||
span: Span)
|
||||
-> ty::t {
|
||||
match kind {
|
||||
&UnsizeLength(len) => match get(ty).sty {
|
||||
ty_vec(t, Some(n)) => {
|
||||
assert!(len == n);
|
||||
mk_vec(cx, t, None)
|
||||
}
|
||||
_ => cx.sess.span_bug(span,
|
||||
format!("UnsizeLength with bad sty: {}",
|
||||
ty_to_string(cx, ty)).as_slice())
|
||||
},
|
||||
&UnsizeStruct(box ref k, tp_index) => match get(ty).sty {
|
||||
ty_struct(did, ref substs) => {
|
||||
let ty_substs = substs.types.get_slice(subst::TypeSpace);
|
||||
let new_ty = unsize_ty(cx, ty_substs[tp_index], k, span);
|
||||
let mut unsized_substs = substs.clone();
|
||||
unsized_substs.types.get_mut_slice(subst::TypeSpace)[tp_index] = new_ty;
|
||||
mk_struct(cx, did, unsized_substs)
|
||||
}
|
||||
_ => cx.sess.span_bug(span,
|
||||
format!("UnsizeStruct with bad sty: {}",
|
||||
ty_to_string(cx, ty)).as_slice())
|
||||
},
|
||||
&UnsizeVtable(bounds, def_id, ref substs) => {
|
||||
mk_trait(cx, def_id, substs.clone(), bounds)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3268,11 +3393,11 @@ pub fn adjust_ty(cx: &ctxt,
|
||||
impl AutoRef {
|
||||
pub fn map_region(&self, f: |Region| -> Region) -> AutoRef {
|
||||
match *self {
|
||||
ty::AutoPtr(r, m) => ty::AutoPtr(f(r), m),
|
||||
ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(f(r), m),
|
||||
ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(f(r), m),
|
||||
ty::AutoPtr(r, m, None) => ty::AutoPtr(f(r), m, None),
|
||||
ty::AutoPtr(r, m, Some(ref a)) => ty::AutoPtr(f(r), m, Some(box a.map_region(f))),
|
||||
ty::AutoUnsize(ref k) => ty::AutoUnsize(k.clone()),
|
||||
ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.clone()),
|
||||
ty::AutoUnsafe(m) => ty::AutoUnsafe(m),
|
||||
ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(f(r), m),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3423,8 +3548,6 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
||||
ast::ExprUnboxedFn(..) |
|
||||
ast::ExprBlock(..) |
|
||||
ast::ExprRepeat(..) |
|
||||
ast::ExprVstore(_, ast::ExprVstoreSlice) |
|
||||
ast::ExprVstore(_, ast::ExprVstoreMutSlice) |
|
||||
ast::ExprVec(..) => {
|
||||
RvalueDpsExpr
|
||||
}
|
||||
@ -3474,8 +3597,7 @@ pub fn expr_kind(tcx: &ctxt, expr: &ast::Expr) -> ExprKind {
|
||||
ast::ExprLit(_) | // Note: LitStr is carved out above
|
||||
ast::ExprUnary(..) |
|
||||
ast::ExprAddrOf(..) |
|
||||
ast::ExprBinary(..) |
|
||||
ast::ExprVstore(_, ast::ExprVstoreUniq) => {
|
||||
ast::ExprBinary(..) => {
|
||||
RvalueDatumExpr
|
||||
}
|
||||
|
||||
@ -3580,6 +3702,7 @@ pub fn ty_sort_string(cx: &ctxt, t: t) -> String {
|
||||
}
|
||||
}
|
||||
ty_err => "type error".to_string(),
|
||||
ty_open(_) => "opened DST".to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -4941,15 +5064,12 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
|
||||
ty_uniq(_) => {
|
||||
byte!(10);
|
||||
}
|
||||
ty_vec(m, Some(n)) => {
|
||||
ty_vec(_, Some(n)) => {
|
||||
byte!(11);
|
||||
mt(&mut state, m);
|
||||
n.hash(&mut state);
|
||||
1u8.hash(&mut state);
|
||||
}
|
||||
ty_vec(m, None) => {
|
||||
ty_vec(_, None) => {
|
||||
byte!(11);
|
||||
mt(&mut state, m);
|
||||
0u8.hash(&mut state);
|
||||
}
|
||||
ty_ptr(m) => {
|
||||
@ -4998,6 +5118,7 @@ pub fn hash_crate_independent(tcx: &ctxt, t: t, svh: &Svh) -> u64 {
|
||||
hash!(p.idx);
|
||||
did(&mut state, p.def_id);
|
||||
}
|
||||
ty_open(_) => byte!(22),
|
||||
ty_infer(_) => unreachable!(),
|
||||
ty_err => byte!(23),
|
||||
ty_unboxed_closure(d, r) => {
|
||||
@ -5220,6 +5341,7 @@ pub fn accumulate_lifetimes_in_type(accumulator: &mut Vec<ty::Region>,
|
||||
ty_tup(_) |
|
||||
ty_param(_) |
|
||||
ty_infer(_) |
|
||||
ty_open(_) |
|
||||
ty_err => {}
|
||||
}
|
||||
})
|
||||
|
@ -273,6 +273,18 @@ impl TypeFoldable for ty::Generics {
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeFoldable for ty::UnsizeKind {
|
||||
fn fold_with<F:TypeFolder>(&self, folder: &mut F) -> ty::UnsizeKind {
|
||||
match *self {
|
||||
ty::UnsizeLength(len) => ty::UnsizeLength(len),
|
||||
ty::UnsizeStruct(box ref k, n) => ty::UnsizeStruct(box k.fold_with(folder), n),
|
||||
ty::UnsizeVtable(bounds, def_id, ref substs) => {
|
||||
ty::UnsizeVtable(bounds.fold_with(folder), def_id, substs.fold_with(folder))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// "super" routines: these are the default implementations for TypeFolder.
|
||||
//
|
||||
@ -360,8 +372,11 @@ pub fn super_fold_sty<T:TypeFolder>(this: &mut T,
|
||||
ty::ty_ptr(ref tm) => {
|
||||
ty::ty_ptr(tm.fold_with(this))
|
||||
}
|
||||
ty::ty_vec(ref tm, sz) => {
|
||||
ty::ty_vec(tm.fold_with(this), sz)
|
||||
ty::ty_vec(typ, sz) => {
|
||||
ty::ty_vec(typ.fold_with(this), sz)
|
||||
}
|
||||
ty::ty_open(typ) => {
|
||||
ty::ty_open(typ.fold_with(this))
|
||||
}
|
||||
ty::ty_enum(tid, ref substs) => {
|
||||
ty::ty_enum(tid, substs.fold_with(this))
|
||||
@ -420,11 +435,13 @@ pub fn super_fold_autoref<T:TypeFolder>(this: &mut T,
|
||||
-> ty::AutoRef
|
||||
{
|
||||
match *autoref {
|
||||
ty::AutoPtr(r, m) => ty::AutoPtr(r.fold_with(this), m),
|
||||
ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(r.fold_with(this), m),
|
||||
ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(r.fold_with(this), m),
|
||||
ty::AutoPtr(r, m, None) => ty::AutoPtr(this.fold_region(r), m, None),
|
||||
ty::AutoPtr(r, m, Some(ref a)) => {
|
||||
ty::AutoPtr(this.fold_region(r), m, Some(box super_fold_autoref(this, &**a)))
|
||||
}
|
||||
ty::AutoUnsafe(m) => ty::AutoUnsafe(m),
|
||||
ty::AutoBorrowObj(r, m) => ty::AutoBorrowObj(r.fold_with(this), m),
|
||||
ty::AutoUnsize(ref k) => ty::AutoUnsize(k.fold_with(this)),
|
||||
ty::AutoUnsizeUniq(ref k) => ty::AutoUnsizeUniq(k.fold_with(this)),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,10 +398,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option<ty::t> {
|
||||
Some(ty::mk_mach_float(ft))
|
||||
}
|
||||
ast::TyStr => {
|
||||
span_err!(tcx.sess, ast_ty.span, E0037,
|
||||
"bare `str` is not a type");
|
||||
// return /something/ so they can at least get more errors
|
||||
Some(ty::mk_uniq(tcx, ty::mk_str(tcx)))
|
||||
Some(ty::mk_str(tcx))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -462,21 +459,7 @@ pub fn ast_ty_to_builtin_ty<AC:AstConv,
|
||||
rscope,
|
||||
&mt,
|
||||
Uniq,
|
||||
|typ| {
|
||||
match ty::get(typ).sty {
|
||||
ty::ty_str => {
|
||||
span_err!(this.tcx().sess, path.span, E0111,
|
||||
"`Box<str>` is not a type");
|
||||
ty::mk_err()
|
||||
}
|
||||
ty::ty_vec(_, None) => {
|
||||
span_err!(this.tcx().sess, path.span, E0112,
|
||||
"`Box<[T]>` is not a type");
|
||||
ty::mk_err()
|
||||
}
|
||||
_ => ty::mk_uniq(this.tcx(), typ),
|
||||
}
|
||||
}))
|
||||
|typ| ty::mk_uniq(this.tcx(), typ)));
|
||||
}
|
||||
span_err!(this.tcx().sess, path.span, E0113,
|
||||
"not enough type parameters supplied to `Box<T>`");
|
||||
@ -537,12 +520,6 @@ enum PointerTy {
|
||||
Uniq
|
||||
}
|
||||
|
||||
fn ast_ty_to_mt<AC:AstConv, RS:RegionScope>(this: &AC,
|
||||
rscope: &RS,
|
||||
ty: &ast::Ty) -> ty::mt {
|
||||
ty::mt {ty: ast_ty_to_ty(this, rscope, ty), mutbl: ast::MutImmutable}
|
||||
}
|
||||
|
||||
pub fn trait_ref_for_unboxed_function<AC:AstConv,
|
||||
RS:RegionScope>(
|
||||
this: &AC,
|
||||
@ -601,11 +578,8 @@ fn mk_pointer<AC:AstConv,
|
||||
|
||||
match a_seq_ty.ty.node {
|
||||
ast::TyVec(ref ty) => {
|
||||
let mut mt = ast_ty_to_mt(this, rscope, &**ty);
|
||||
if a_seq_ty.mutbl == ast::MutMutable {
|
||||
mt.mutbl = ast::MutMutable;
|
||||
}
|
||||
return constr(ty::mk_vec(tcx, mt, None));
|
||||
let ty = ast_ty_to_ty(this, rscope, &**ty);
|
||||
return constr(ty::mk_vec(tcx, ty, None));
|
||||
}
|
||||
ast::TyUnboxedFn(ref unboxed_function) => {
|
||||
let ty::TraitRef {
|
||||
@ -662,10 +636,24 @@ fn mk_pointer<AC:AstConv,
|
||||
Some(&def::DefTrait(trait_def_id)) => {
|
||||
let result = ast_path_to_trait_ref(
|
||||
this, rscope, trait_def_id, None, path);
|
||||
let trait_store = match ptr_ty {
|
||||
Uniq => ty::UniqTraitStore,
|
||||
let static_region = match ptr_ty {
|
||||
RPtr(r) if r == ty::ReStatic => true,
|
||||
_ => false
|
||||
};
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
static_region);
|
||||
let tr = ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
bounds);
|
||||
return match ptr_ty {
|
||||
Uniq => {
|
||||
return ty::mk_uniq(tcx, tr);
|
||||
}
|
||||
RPtr(r) => {
|
||||
ty::RegionTraitStore(r, a_seq_ty.mutbl)
|
||||
return ty::mk_rptr(tcx, r, ty::mt{mutbl: a_seq_ty.mutbl, ty: tr});
|
||||
}
|
||||
_ => {
|
||||
tcx.sess.span_err(
|
||||
@ -675,24 +663,6 @@ fn mk_pointer<AC:AstConv,
|
||||
return ty::mk_err();
|
||||
}
|
||||
};
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
trait_store);
|
||||
let tr = ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
bounds);
|
||||
// We could just match on ptr_ty, but we need to pass a trait
|
||||
// store to conv_builtin_bounds, so mathc twice for now.
|
||||
return match trait_store {
|
||||
ty::UniqTraitStore => {
|
||||
return ty::mk_uniq(tcx, tr);
|
||||
}
|
||||
ty::RegionTraitStore(r, m) => {
|
||||
return ty::mk_rptr(tcx, r, ty::mt{mutbl: m, ty: tr});
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@ -738,10 +708,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
|ty| ty::mk_uniq(tcx, ty))
|
||||
}
|
||||
ast::TyVec(ty) => {
|
||||
tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type");
|
||||
// return /something/ so they can at least get more errors
|
||||
let vec_ty = ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty), None);
|
||||
ty::mk_uniq(tcx, vec_ty)
|
||||
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty), None)
|
||||
}
|
||||
ast::TyPtr(ref mt) => {
|
||||
ty::mk_ptr(tcx, ty::mt {
|
||||
@ -777,15 +744,14 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
let bound_region = opt_ast_region_to_region(this, rscope,
|
||||
ast_ty.span, region);
|
||||
|
||||
let store = ty::RegionTraitStore(bound_region, ast::MutMutable);
|
||||
|
||||
// Use corresponding trait store to figure out default bounds
|
||||
// if none were specified.
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
ast_ty.span,
|
||||
&f.bounds,
|
||||
store);
|
||||
bound_region == ty::ReStatic);
|
||||
|
||||
let store = ty::RegionTraitStore(bound_region, ast::MutMutable);
|
||||
let fn_decl = ty_of_closure(this,
|
||||
ast_ty.id,
|
||||
f.fn_style,
|
||||
@ -803,7 +769,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
ast_ty.span,
|
||||
&f.bounds,
|
||||
ty::UniqTraitStore);
|
||||
false);
|
||||
|
||||
let fn_decl = ty_of_closure(this,
|
||||
ast_ty.id,
|
||||
@ -841,15 +807,17 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
_ => { },
|
||||
}
|
||||
match a_def {
|
||||
def::DefTrait(_) => {
|
||||
let path_str = path_to_string(path);
|
||||
tcx.sess.span_err(
|
||||
ast_ty.span,
|
||||
format!("reference to trait `{name}` where a \
|
||||
type is expected; try `Box<{name}>` or \
|
||||
`&{name}`",
|
||||
name=path_str).as_slice());
|
||||
ty::mk_err()
|
||||
def::DefTrait(trait_def_id) => {
|
||||
let result = ast_path_to_trait_ref(
|
||||
this, rscope, trait_def_id, None, path);
|
||||
let bounds = conv_builtin_bounds(this.tcx(),
|
||||
path.span,
|
||||
bounds,
|
||||
false);
|
||||
ty::mk_trait(tcx,
|
||||
result.def_id,
|
||||
result.substs.clone(),
|
||||
bounds)
|
||||
}
|
||||
def::DefTy(did) | def::DefStruct(did) => {
|
||||
ast_path_to_ty(this, rscope, did, path).ty
|
||||
@ -887,10 +855,10 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:RegionScope>(
|
||||
Ok(ref r) => {
|
||||
match *r {
|
||||
const_eval::const_int(i) =>
|
||||
ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty),
|
||||
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty),
|
||||
Some(i as uint)),
|
||||
const_eval::const_uint(i) =>
|
||||
ty::mk_vec(tcx, ast_ty_to_mt(this, rscope, &*ty),
|
||||
ty::mk_vec(tcx, ast_ty_to_ty(this, rscope, &*ty),
|
||||
Some(i as uint)),
|
||||
_ => {
|
||||
tcx.sess.span_fatal(
|
||||
@ -1211,7 +1179,7 @@ pub fn ty_of_closure<AC:AstConv>(
|
||||
fn conv_builtin_bounds(tcx: &ty::ctxt,
|
||||
span: Span,
|
||||
ast_bounds: &Option<OwnedSlice<ast::TyParamBound>>,
|
||||
store: ty::TraitStore)
|
||||
static_region: bool)
|
||||
-> ty::BuiltinBounds {
|
||||
//! Converts a list of bounds from the AST into a `BuiltinBounds`
|
||||
//! struct. Reports an error if any of the bounds that appear
|
||||
@ -1224,8 +1192,8 @@ fn conv_builtin_bounds(tcx: &ty::ctxt,
|
||||
//! override this with an empty bounds list, e.g. "Box<fn:()>" or
|
||||
//! "Box<Trait:>".
|
||||
|
||||
match (ast_bounds, store) {
|
||||
(&Some(ref bound_vec), _) => {
|
||||
match ast_bounds {
|
||||
&Some(ref bound_vec) => {
|
||||
let mut builtin_bounds = ty::empty_builtin_bounds();
|
||||
for ast_bound in bound_vec.iter() {
|
||||
match *ast_bound {
|
||||
@ -1265,12 +1233,10 @@ fn conv_builtin_bounds(tcx: &ty::ctxt,
|
||||
builtin_bounds
|
||||
},
|
||||
// &'static Trait is sugar for &'static Trait:'static.
|
||||
(&None, ty::RegionTraitStore(ty::ReStatic, _)) => {
|
||||
&None if static_region => {
|
||||
let mut set = ty::empty_builtin_bounds(); set.add(ty::BoundStatic); set
|
||||
}
|
||||
// No bounds are automatically applied for &'r Trait or ~Trait
|
||||
(&None, ty::RegionTraitStore(..)) |
|
||||
(&None, ty::UniqTraitStore) => ty::empty_builtin_bounds(),
|
||||
&None => ty::empty_builtin_bounds(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -658,10 +658,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
|
||||
let (elt_type, region_var, mutbl, fixed) = match *structure_of(fcx,
|
||||
pat.span,
|
||||
expected) {
|
||||
ty::ty_vec(mt, Some(fixed)) =>
|
||||
(mt.ty, default_region_var, ast::MutImmutable, Some(fixed)),
|
||||
ty::ty_vec(ty, Some(fixed)) =>
|
||||
(ty, default_region_var, ast::MutImmutable, Some(fixed)),
|
||||
ty::ty_uniq(t) => match ty::get(t).sty {
|
||||
ty::ty_vec(mt, None) => {
|
||||
ty::ty_vec(ty, None) => {
|
||||
fcx.type_error_message(pat.span,
|
||||
|_| {
|
||||
"unique vector patterns are no \
|
||||
@ -669,7 +669,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
|
||||
},
|
||||
expected,
|
||||
None);
|
||||
(mt.ty, default_region_var, ast::MutImmutable, None)
|
||||
(ty, default_region_var, ast::MutImmutable, None)
|
||||
}
|
||||
_ => {
|
||||
check_err("a vector pattern".to_string());
|
||||
@ -677,7 +677,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: &ast::Pat, expected: ty::t) {
|
||||
}
|
||||
},
|
||||
ty::ty_rptr(r, mt) => match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(mt, None) => (mt.ty, r, mt.mutbl, None),
|
||||
ty::ty_vec(ty, None) => (ty, r, mt.mutbl, None),
|
||||
_ => {
|
||||
check_err("a vector pattern".to_string());
|
||||
return;
|
||||
|
@ -77,3 +77,17 @@ pub fn coerce(fcx: &FnCtxt, sp: Span, expected: ty::t, expr: &ast::Expr) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coerce_with_fn(fcx: &FnCtxt,
|
||||
sp: Span,
|
||||
expected: ty::t,
|
||||
expr: &ast::Expr,
|
||||
handle_err: |Span, ty::t, ty::t, &ty::type_err|) {
|
||||
let expr_ty = fcx.expr_ty(expr);
|
||||
match fcx.mk_assignty(expr, expr_ty, expected) {
|
||||
result::Ok(()) => { /* ok */ }
|
||||
result::Err(ref err) => {
|
||||
handle_err(sp, expected, expr_ty, err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -356,23 +356,14 @@ impl<'a> LookupContext<'a> {
|
||||
let span = self.self_expr.map_or(self.span, |e| e.span);
|
||||
let self_expr_id = self.self_expr.map(|e| e.id);
|
||||
|
||||
let (self_ty, autoderefs, result) =
|
||||
let (_, _, result) =
|
||||
check::autoderef(
|
||||
self.fcx, span, self_ty, self_expr_id, PreferMutLvalue,
|
||||
|self_ty, autoderefs| self.search_step(self_ty, autoderefs));
|
||||
|
||||
match result {
|
||||
Some(Some(result)) => Some(result),
|
||||
_ => {
|
||||
if self.is_overloaded_deref() {
|
||||
// If we are searching for an overloaded deref, no
|
||||
// need to try coercing a `~[T]` to an `&[T]` and
|
||||
// searching for an overloaded deref on *that*.
|
||||
None
|
||||
} else {
|
||||
self.search_for_autosliced_method(self_ty, autoderefs)
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
@ -408,6 +399,16 @@ impl<'a> LookupContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
// If we are searching for an overloaded deref, no
|
||||
// need to try coercing a `~[T]` to an `&[T]` and
|
||||
// searching for an overloaded deref on *that*.
|
||||
if !self.is_overloaded_deref() {
|
||||
match self.search_for_autofatptrd_method(self_ty, autoderefs) {
|
||||
Some(result) => return Some(Some(result)),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't autoderef if we aren't supposed to.
|
||||
if self.autoderef_receiver == DontAutoderefReceiver {
|
||||
Some(None)
|
||||
@ -441,13 +442,10 @@ impl<'a> LookupContext<'a> {
|
||||
let span = self.self_expr.map_or(self.span, |e| e.span);
|
||||
check::autoderef(self.fcx, span, self_ty, None, PreferMutLvalue, |self_ty, _| {
|
||||
match get(self_ty).sty {
|
||||
ty_uniq(ty) | ty_rptr(_, mt {ty, ..}) => match get(ty).sty{
|
||||
ty_trait(box TyTrait { def_id, ref substs, .. }) => {
|
||||
self.push_inherent_candidates_from_object(def_id, substs);
|
||||
self.push_inherent_impl_candidates_for_type(def_id);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
ty_trait(box TyTrait { def_id, ref substs, .. }) => {
|
||||
self.push_inherent_candidates_from_object(def_id, substs);
|
||||
self.push_inherent_impl_candidates_for_type(def_id);
|
||||
}
|
||||
ty_enum(did, _) |
|
||||
ty_struct(did, _) |
|
||||
ty_unboxed_closure(did, _) => {
|
||||
@ -830,23 +828,22 @@ impl<'a> LookupContext<'a> {
|
||||
self_ty: ty::t,
|
||||
autoderefs: uint)
|
||||
-> Option<MethodCallee> {
|
||||
let (self_ty, auto_deref_ref) =
|
||||
self.consider_reborrow(self_ty, autoderefs);
|
||||
|
||||
// Hacky. For overloaded derefs, there may be an adjustment
|
||||
// added to the expression from the outside context, so we do not store
|
||||
// an explicit adjustment, but rather we hardwire the single deref
|
||||
// that occurs in trans and mem_categorization.
|
||||
let adjustment = match self.self_expr {
|
||||
Some(expr) => Some((expr.id, ty::AutoDerefRef(auto_deref_ref))),
|
||||
None => return None
|
||||
};
|
||||
if self.self_expr.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let (self_ty, auto_deref_ref) = self.consider_reborrow(self_ty, autoderefs);
|
||||
let adjustment = Some((self.self_expr.unwrap().id, ty::AutoDerefRef(auto_deref_ref)));
|
||||
|
||||
match self.search_for_method(self_ty) {
|
||||
None => None,
|
||||
Some(method) => {
|
||||
debug!("(searching for autoderef'd method) writing \
|
||||
adjustment {:?} for {}", adjustment, self.ty_to_string( self_ty));
|
||||
adjustment {:?} for {}", adjustment, self.ty_to_string(self_ty));
|
||||
match adjustment {
|
||||
Some((self_expr_id, adj)) => {
|
||||
self.fcx.write_adjustment(self_expr_id, adj);
|
||||
@ -890,16 +887,10 @@ impl<'a> LookupContext<'a> {
|
||||
ty::ty_rptr(_, self_mt) => {
|
||||
let region =
|
||||
self.infcx().next_region_var(infer::Autoref(self.span));
|
||||
let (extra_derefs, auto) = match ty::get(self_mt.ty).sty {
|
||||
ty::ty_vec(_, None) => (0, ty::AutoBorrowVec(region, self_mt.mutbl)),
|
||||
ty::ty_str => (0, ty::AutoBorrowVec(region, self_mt.mutbl)),
|
||||
ty::ty_trait(..) => (0, ty::AutoBorrowObj(region, self_mt.mutbl)),
|
||||
_ => (1, ty::AutoPtr(region, self_mt.mutbl)),
|
||||
};
|
||||
(ty::mk_rptr(tcx, region, self_mt),
|
||||
ty::AutoDerefRef {
|
||||
autoderefs: autoderefs + extra_derefs,
|
||||
autoref: Some(auto)})
|
||||
autoderefs: autoderefs + 1,
|
||||
autoref: Some(ty::AutoPtr(region, self_mt.mutbl, None))})
|
||||
}
|
||||
_ => {
|
||||
(self_ty,
|
||||
@ -920,15 +911,18 @@ impl<'a> LookupContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn auto_slice_vec(&self, mt: ty::mt, autoderefs: uint) -> Option<MethodCallee> {
|
||||
// Takes an [T] - an unwrapped DST pointer (either ~ or &)
|
||||
// [T] to &[T] or &&[T] (note that we started with a &[T] or ~[T] which has
|
||||
// been implicitly derefed).
|
||||
fn auto_slice_vec(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> {
|
||||
let tcx = self.tcx();
|
||||
debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, mt.ty));
|
||||
debug!("auto_slice_vec {}", ppaux::ty_to_string(tcx, ty));
|
||||
|
||||
// First try to borrow to a slice
|
||||
let entry = self.search_for_some_kind_of_autorefd_method(
|
||||
AutoBorrowVec, autoderefs, [MutImmutable, MutMutable],
|
||||
|r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable],
|
||||
|m,r| ty::mk_slice(tcx, r,
|
||||
ty::mt {ty:mt.ty, mutbl:m}));
|
||||
ty::mt {ty:ty, mutbl:m}));
|
||||
|
||||
if entry.is_some() {
|
||||
return entry;
|
||||
@ -936,10 +930,11 @@ impl<'a> LookupContext<'a> {
|
||||
|
||||
// Then try to borrow to a slice *and* borrow a pointer.
|
||||
self.search_for_some_kind_of_autorefd_method(
|
||||
AutoBorrowVecRef, autoderefs, [MutImmutable, MutMutable],
|
||||
|m,r| {
|
||||
|r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))),
|
||||
autoderefs, [MutImmutable, MutMutable],
|
||||
|m, r| {
|
||||
let slice_ty = ty::mk_slice(tcx, r,
|
||||
ty::mt {ty:mt.ty, mutbl:m});
|
||||
ty::mt {ty:ty, mutbl:m});
|
||||
// NB: we do not try to autoref to a mutable
|
||||
// pointer. That would be creating a pointer
|
||||
// to a temporary pointer (the borrowed
|
||||
@ -949,22 +944,59 @@ impl<'a> LookupContext<'a> {
|
||||
})
|
||||
}
|
||||
|
||||
// [T, ..len] -> [T] or &[T] or &&[T]
|
||||
fn auto_unsize_vec(&self, ty: ty::t, autoderefs: uint, len: uint) -> Option<MethodCallee> {
|
||||
let tcx = self.tcx();
|
||||
debug!("auto_unsize_vec {}", ppaux::ty_to_string(tcx, ty));
|
||||
|
||||
// First try to borrow to an unsized vec.
|
||||
let entry = self.search_for_some_kind_of_autorefd_method(
|
||||
|_r, _m| AutoUnsize(ty::UnsizeLength(len)),
|
||||
autoderefs, [MutImmutable, MutMutable],
|
||||
|_m, _r| ty::mk_vec(tcx, ty, None));
|
||||
|
||||
if entry.is_some() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Then try to borrow to a slice.
|
||||
let entry = self.search_for_some_kind_of_autorefd_method(
|
||||
|r, m| AutoPtr(r, m, Some(box AutoUnsize(ty::UnsizeLength(len)))),
|
||||
autoderefs, [MutImmutable, MutMutable],
|
||||
|m, r| ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m}));
|
||||
|
||||
if entry.is_some() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
// Then try to borrow to a slice *and* borrow a pointer.
|
||||
self.search_for_some_kind_of_autorefd_method(
|
||||
|r, m| AutoPtr(r, m,
|
||||
Some(box AutoPtr(r, m,
|
||||
Some(box AutoUnsize(ty::UnsizeLength(len)))))),
|
||||
autoderefs, [MutImmutable, MutMutable],
|
||||
|m, r| {
|
||||
let slice_ty = ty::mk_slice(tcx, r, ty::mt {ty:ty, mutbl:m});
|
||||
ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:MutImmutable})
|
||||
})
|
||||
}
|
||||
|
||||
fn auto_slice_str(&self, autoderefs: uint) -> Option<MethodCallee> {
|
||||
let tcx = self.tcx();
|
||||
debug!("auto_slice_str");
|
||||
|
||||
let entry = self.search_for_some_kind_of_autorefd_method(
|
||||
AutoBorrowVec, autoderefs, [MutImmutable],
|
||||
|_m,r| ty::mk_str_slice(tcx, r, MutImmutable));
|
||||
|r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable],
|
||||
|_m, r| ty::mk_str_slice(tcx, r, MutImmutable));
|
||||
|
||||
if entry.is_some() {
|
||||
return entry;
|
||||
}
|
||||
|
||||
self.search_for_some_kind_of_autorefd_method(
|
||||
AutoBorrowVecRef, autoderefs, [MutImmutable],
|
||||
|m,r| {
|
||||
|r, m| AutoPtr(r, ast::MutImmutable, Some( box AutoPtr(r, m, None))),
|
||||
autoderefs, [MutImmutable],
|
||||
|m, r| {
|
||||
let slice_ty = ty::mk_str_slice(tcx, r, m);
|
||||
ty::mk_rptr(tcx, r, ty::mt {ty:slice_ty, mutbl:m})
|
||||
})
|
||||
@ -972,6 +1004,7 @@ impl<'a> LookupContext<'a> {
|
||||
|
||||
// Coerce Box/&Trait instances to &Trait.
|
||||
fn auto_slice_trait(&self, ty: ty::t, autoderefs: uint) -> Option<MethodCallee> {
|
||||
debug!("auto_slice_trait");
|
||||
match ty::get(ty).sty {
|
||||
ty_trait(box ty::TyTrait {
|
||||
def_id: trt_did,
|
||||
@ -980,7 +1013,8 @@ impl<'a> LookupContext<'a> {
|
||||
.. }) => {
|
||||
let tcx = self.tcx();
|
||||
self.search_for_some_kind_of_autorefd_method(
|
||||
AutoBorrowObj, autoderefs, [MutImmutable, MutMutable],
|
||||
|r, m| AutoPtr(r, m, None),
|
||||
autoderefs, [MutImmutable, MutMutable],
|
||||
|m, r| {
|
||||
let tr = ty::mk_trait(tcx, trt_did, trt_substs.clone(), b);
|
||||
ty::mk_rptr(tcx, r, ty::mt{ ty: tr, mutbl: m })
|
||||
@ -990,31 +1024,24 @@ impl<'a> LookupContext<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn search_for_autosliced_method(&self,
|
||||
self_ty: ty::t,
|
||||
autoderefs: uint)
|
||||
-> Option<MethodCallee> {
|
||||
fn search_for_autofatptrd_method(&self,
|
||||
self_ty: ty::t,
|
||||
autoderefs: uint)
|
||||
-> Option<MethodCallee> {
|
||||
/*!
|
||||
* Searches for a candidate by converting things like
|
||||
* `~[]` to `&[]`.
|
||||
*/
|
||||
|
||||
debug!("search_for_autosliced_method {}", ppaux::ty_to_string(self.tcx(), self_ty));
|
||||
let tcx = self.tcx();
|
||||
debug!("search_for_autofatptrd_method {}", ppaux::ty_to_string(tcx, self_ty));
|
||||
|
||||
let sty = ty::get(self_ty).sty.clone();
|
||||
match sty {
|
||||
ty_rptr(_, mt) => match ty::get(mt.ty).sty {
|
||||
ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs),
|
||||
ty_trait(..) => self.auto_slice_trait(mt.ty, autoderefs),
|
||||
_ => None
|
||||
},
|
||||
ty_uniq(t) => match ty::get(t).sty {
|
||||
ty_vec(mt, None) => self.auto_slice_vec(mt, autoderefs),
|
||||
ty_str => self.auto_slice_str(autoderefs),
|
||||
ty_trait(..) => self.auto_slice_trait(t, autoderefs),
|
||||
_ => None
|
||||
},
|
||||
ty_vec(mt, Some(_)) => self.auto_slice_vec(mt, autoderefs),
|
||||
ty_vec(ty, Some(len)) => self.auto_unsize_vec(ty, autoderefs, len),
|
||||
ty_vec(ty, None) => self.auto_slice_vec(ty, autoderefs),
|
||||
ty_str => self.auto_slice_str(autoderefs),
|
||||
ty_trait(..) => self.auto_slice_trait(self_ty, autoderefs),
|
||||
|
||||
ty_closure(..) => {
|
||||
// This case should probably be handled similarly to
|
||||
@ -1042,10 +1069,10 @@ impl<'a> LookupContext<'a> {
|
||||
ty_param(..) | ty_nil | ty_bot | ty_bool |
|
||||
ty_char | ty_int(..) | ty_uint(..) |
|
||||
ty_float(..) | ty_enum(..) | ty_ptr(..) | ty_struct(..) |
|
||||
ty_unboxed_closure(..) | ty_tup(..) |
|
||||
ty_unboxed_closure(..) | ty_tup(..) | ty_open(..) |
|
||||
ty_str | ty_vec(..) | ty_trait(..) | ty_closure(..) => {
|
||||
self.search_for_some_kind_of_autorefd_method(
|
||||
AutoPtr, autoderefs, [MutImmutable, MutMutable],
|
||||
|r, m| AutoPtr(r, m, None), autoderefs, [MutImmutable, MutMutable],
|
||||
|m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m}))
|
||||
}
|
||||
|
||||
@ -1073,8 +1100,8 @@ impl<'a> LookupContext<'a> {
|
||||
Some(expr) => Some(expr.id),
|
||||
None => {
|
||||
assert_eq!(autoderefs, 0);
|
||||
assert_eq!(kind(ty::ReEmpty, ast::MutImmutable),
|
||||
ty::AutoPtr(ty::ReEmpty, ast::MutImmutable));
|
||||
assert!(kind(ty::ReEmpty, ast::MutImmutable) ==
|
||||
ty::AutoPtr(ty::ReEmpty, ast::MutImmutable, None));
|
||||
None
|
||||
}
|
||||
};
|
||||
@ -1442,17 +1469,15 @@ impl<'a> LookupContext<'a> {
|
||||
match ty::get(rcvr_ty).sty {
|
||||
ty::ty_rptr(_, mt) => {
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => false,
|
||||
ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
|
||||
mutability_matches(mt.mutbl, m) &&
|
||||
rcvr_matches_object(self_did, candidate)
|
||||
}
|
||||
_ => mutability_matches(mt.mutbl, m) &&
|
||||
rcvr_matches_ty(self.fcx, mt.ty, candidate),
|
||||
rcvr_matches_ty(self.fcx, mt.ty, candidate)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
@ -1462,7 +1487,6 @@ impl<'a> LookupContext<'a> {
|
||||
match ty::get(rcvr_ty).sty {
|
||||
ty::ty_uniq(typ) => {
|
||||
match ty::get(typ).sty {
|
||||
ty::ty_vec(_, None) | ty::ty_str => false,
|
||||
ty::ty_trait(box ty::TyTrait { def_id: self_did, .. }) => {
|
||||
rcvr_matches_object(self_did, candidate)
|
||||
}
|
||||
|
@ -560,21 +560,6 @@ fn check_fn<'a>(ccx: &'a CrateCtxt<'a>,
|
||||
|
||||
check_block_with_expected(&fcx, body, ExpectHasType(ret_ty));
|
||||
|
||||
// We unify the tail expr's type with the
|
||||
// function result type, if there is a tail expr.
|
||||
match body.expr {
|
||||
Some(ref tail_expr) => {
|
||||
// Special case: we print a special error if there appears
|
||||
// to be do-block/for-loop confusion
|
||||
demand::suptype_with_fn(&fcx, tail_expr.span, false,
|
||||
fcx.ret_ty, fcx.expr_ty(&**tail_expr),
|
||||
|sp, e, a, s| {
|
||||
fcx.report_mismatched_return_types(sp, e, a, s);
|
||||
});
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
for (input, arg) in decl.inputs.iter().zip(arg_tys.iter()) {
|
||||
fcx.write_ty(input.id, *arg);
|
||||
}
|
||||
@ -1164,7 +1149,7 @@ fn check_cast(fcx: &FnCtxt,
|
||||
if ty::type_is_scalar(t_1) {
|
||||
// Supply the type as a hint so as to influence integer
|
||||
// literals and other things that might care.
|
||||
check_expr_with_hint(fcx, e, t_1)
|
||||
check_expr_with_expectation(fcx, e, ExpectCastableToType(t_1))
|
||||
} else {
|
||||
check_expr(fcx, e)
|
||||
}
|
||||
@ -2048,7 +2033,6 @@ fn check_argument_types(fcx: &FnCtxt,
|
||||
}
|
||||
|
||||
check_expr_coercable_to_type(fcx, &**arg, formal_ty);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2436,8 +2420,20 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
// The tightest thing we can say is "must unify with
|
||||
// else branch". Note that in the case of a "has type"
|
||||
// constraint, this limitation does not hold.
|
||||
let expected = expected.only_has_type();
|
||||
|
||||
// If the expected type is just a type variable, then don't use
|
||||
// an expected type. Otherwise, we might write parts of the type
|
||||
// when checking the 'then' block which are incompatible with the
|
||||
// 'else' branch.
|
||||
let expected = match expected.only_has_type() {
|
||||
ExpectHasType(ety) => {
|
||||
match infer::resolve_type(fcx.infcx(), Some(sp), ety, force_tvar) {
|
||||
Ok(rty) if !ty::type_is_ty_var(rty) => ExpectHasType(rty),
|
||||
_ => NoExpectation
|
||||
}
|
||||
}
|
||||
_ => NoExpectation
|
||||
};
|
||||
check_block_with_expected(fcx, then_blk, expected);
|
||||
let then_ty = fcx.node_ty(then_blk.id);
|
||||
check_expr_with_expectation(fcx, &**else_expr, expected);
|
||||
@ -3070,96 +3066,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
|
||||
type ExprCheckerWithTy = fn(&FnCtxt, &ast::Expr, ty::t);
|
||||
|
||||
fn check_fn_for_vec_elements_expected(fcx: &FnCtxt,
|
||||
expected: Expectation)
|
||||
-> (ExprCheckerWithTy, ty::t) {
|
||||
let tcx = fcx.ccx.tcx;
|
||||
let (coerce, t) = match expected {
|
||||
// If we're given an expected type, we can try to coerce to it
|
||||
ExpectHasType(t) if ty::type_is_vec(t) => (true, ty::sequence_element_type(tcx, t)),
|
||||
// Otherwise we just leave the type to be resolved later
|
||||
_ => (false, fcx.infcx().next_ty_var())
|
||||
};
|
||||
if coerce {
|
||||
(check_expr_coercable_to_type, t)
|
||||
} else {
|
||||
(check_expr_has_type, t)
|
||||
}
|
||||
}
|
||||
|
||||
let tcx = fcx.ccx.tcx;
|
||||
let id = expr.id;
|
||||
match expr.node {
|
||||
ast::ExprVstore(ev, vst) => {
|
||||
let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
|
||||
let typ = match ev.node {
|
||||
ast::ExprVec(ref args) => {
|
||||
let mutability = match vst {
|
||||
ast::ExprVstoreMutSlice => ast::MutMutable,
|
||||
_ => ast::MutImmutable,
|
||||
};
|
||||
let mut any_error = false;
|
||||
let mut any_bot = false;
|
||||
for e in args.iter() {
|
||||
check(fcx, &**e, t);
|
||||
let arg_t = fcx.expr_ty(&**e);
|
||||
if ty::type_is_error(arg_t) {
|
||||
any_error = true;
|
||||
}
|
||||
else if ty::type_is_bot(arg_t) {
|
||||
any_bot = true;
|
||||
}
|
||||
}
|
||||
if any_error {
|
||||
ty::mk_err()
|
||||
} else if any_bot {
|
||||
ty::mk_bot()
|
||||
} else {
|
||||
ast_expr_vstore_to_ty(fcx, &*ev, vst, ||
|
||||
ty::mt{ ty: ty::mk_vec(tcx,
|
||||
ty::mt {ty: t, mutbl: mutability},
|
||||
None),
|
||||
mutbl: mutability })
|
||||
}
|
||||
}
|
||||
ast::ExprRepeat(ref element, ref count_expr) => {
|
||||
check_expr_with_hint(fcx, &**count_expr, ty::mk_uint());
|
||||
let _ = ty::eval_repeat_count(fcx, &**count_expr);
|
||||
let mutability = match vst {
|
||||
ast::ExprVstoreMutSlice => ast::MutMutable,
|
||||
_ => ast::MutImmutable,
|
||||
};
|
||||
check(fcx, &**element, t);
|
||||
let arg_t = fcx.expr_ty(&**element);
|
||||
if ty::type_is_error(arg_t) {
|
||||
ty::mk_err()
|
||||
} else if ty::type_is_bot(arg_t) {
|
||||
ty::mk_bot()
|
||||
} else {
|
||||
ast_expr_vstore_to_ty(fcx, &*ev, vst, ||
|
||||
ty::mt{ ty: ty::mk_vec(tcx,
|
||||
ty::mt {ty: t, mutbl: mutability},
|
||||
None),
|
||||
mutbl: mutability})
|
||||
}
|
||||
}
|
||||
ast::ExprLit(_) => {
|
||||
if vst == ast::ExprVstoreSlice {
|
||||
span_err!(tcx.sess, expr.span, E0064,
|
||||
"`&\"string\"` has been removed; use `\"string\"` instead");
|
||||
} else {
|
||||
span_err!(tcx.sess, expr.span, E0065,
|
||||
"`box \"string\"` has been removed; use \
|
||||
`\"string\".to_string()` instead");
|
||||
}
|
||||
ty::mk_err()
|
||||
}
|
||||
_ => tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence"),
|
||||
};
|
||||
fcx.write_ty(ev.id, typ);
|
||||
fcx.write_ty(id, typ);
|
||||
}
|
||||
|
||||
ast::ExprBox(ref place, ref subexpr) => {
|
||||
check_expr(fcx, &**place);
|
||||
check_expr(fcx, &**subexpr);
|
||||
@ -3230,7 +3139,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
}
|
||||
}
|
||||
ast::ExprUnary(unop, ref oprnd) => {
|
||||
let expected = expected.only_has_type();
|
||||
let expected_inner = expected.map(fcx, |sty| {
|
||||
match unop {
|
||||
ast::UnBox | ast::UnUniq => match *sty {
|
||||
@ -3337,22 +3245,6 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
hint,
|
||||
lvalue_pref);
|
||||
|
||||
// Note: at this point, we cannot say what the best lifetime
|
||||
// is to use for resulting pointer. We want to use the
|
||||
// shortest lifetime possible so as to avoid spurious borrowck
|
||||
// errors. Moreover, the longest lifetime will depend on the
|
||||
// precise details of the value whose address is being taken
|
||||
// (and how long it is valid), which we don't know yet until type
|
||||
// inference is complete.
|
||||
//
|
||||
// Therefore, here we simply generate a region variable. The
|
||||
// region inferencer will then select the ultimate value.
|
||||
// Finally, borrowck is charged with guaranteeing that the
|
||||
// value whose address was taken can actually be made to live
|
||||
// as long as it needs to live.
|
||||
let region = fcx.infcx().next_region_var(
|
||||
infer::AddrOfRegion(expr.span));
|
||||
|
||||
let tm = ty::mt { ty: fcx.expr_ty(&**oprnd), mutbl: mutbl };
|
||||
let oprnd_t = if ty::type_is_error(tm.ty) {
|
||||
ty::mk_err()
|
||||
@ -3360,7 +3252,31 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
ty::mk_bot()
|
||||
}
|
||||
else {
|
||||
ty::mk_rptr(tcx, region, tm)
|
||||
// Note: at this point, we cannot say what the best lifetime
|
||||
// is to use for resulting pointer. We want to use the
|
||||
// shortest lifetime possible so as to avoid spurious borrowck
|
||||
// errors. Moreover, the longest lifetime will depend on the
|
||||
// precise details of the value whose address is being taken
|
||||
// (and how long it is valid), which we don't know yet until type
|
||||
// inference is complete.
|
||||
//
|
||||
// Therefore, here we simply generate a region variable. The
|
||||
// region inferencer will then select the ultimate value.
|
||||
// Finally, borrowck is charged with guaranteeing that the
|
||||
// value whose address was taken can actually be made to live
|
||||
// as long as it needs to live.
|
||||
match oprnd.node {
|
||||
// String literals are already, implicitly converted to slices.
|
||||
//ast::ExprLit(lit) if ast_util::lit_is_str(lit) => fcx.expr_ty(oprnd),
|
||||
// Empty slices live in static memory.
|
||||
ast::ExprVec(ref elements) if elements.len() == 0 => {
|
||||
ty::mk_rptr(tcx, ty::ReStatic, tm)
|
||||
}
|
||||
_ => {
|
||||
let region = fcx.infcx().next_region_var(infer::AddrOfRegion(expr.span));
|
||||
ty::mk_rptr(tcx, region, tm)
|
||||
}
|
||||
}
|
||||
};
|
||||
fcx.write_ty(id, oprnd_t);
|
||||
}
|
||||
@ -3393,7 +3309,7 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
}
|
||||
},
|
||||
Some(ref e) => {
|
||||
check_expr_has_type(fcx, &**e, ret_ty);
|
||||
check_expr_coercable_to_type(fcx, &**e, ret_ty);
|
||||
}
|
||||
}
|
||||
fcx.write_bot(id);
|
||||
@ -3547,29 +3463,66 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
check_cast(fcx, &**e, &**t, id, expr.span);
|
||||
}
|
||||
ast::ExprVec(ref args) => {
|
||||
let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
|
||||
for e in args.iter() {
|
||||
check(fcx, &**e, t);
|
||||
}
|
||||
let typ = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
|
||||
Some(args.len()));
|
||||
let uty = match expected {
|
||||
ExpectHasType(uty) => {
|
||||
match ty::get(uty).sty {
|
||||
ty::ty_vec(ty, _) => Some(ty),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
||||
let typ = match uty {
|
||||
Some(uty) => {
|
||||
for e in args.iter() {
|
||||
check_expr_coercable_to_type(fcx, &**e, uty);
|
||||
}
|
||||
uty
|
||||
}
|
||||
None => {
|
||||
let t: ty::t = fcx.infcx().next_ty_var();
|
||||
for e in args.iter() {
|
||||
check_expr_has_type(fcx, &**e, t);
|
||||
}
|
||||
t
|
||||
}
|
||||
};
|
||||
let typ = ty::mk_vec(tcx, typ, Some(args.len()));
|
||||
fcx.write_ty(id, typ);
|
||||
}
|
||||
ast::ExprRepeat(ref element, ref count_expr) => {
|
||||
check_expr_has_type(fcx, &**count_expr, ty::mk_uint());
|
||||
let count = ty::eval_repeat_count(fcx, &**count_expr);
|
||||
let (check, t) = check_fn_for_vec_elements_expected(fcx, expected);
|
||||
check(fcx, &**element, t);
|
||||
let element_ty = fcx.expr_ty(&**element);
|
||||
|
||||
let uty = match expected {
|
||||
ExpectHasType(uty) => {
|
||||
match ty::get(uty).sty {
|
||||
ty::ty_vec(ty, _) => Some(ty),
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
_ => None
|
||||
};
|
||||
|
||||
let (element_ty, t) = match uty {
|
||||
Some(uty) => {
|
||||
check_expr_coercable_to_type(fcx, &**element, uty);
|
||||
(uty, uty)
|
||||
}
|
||||
None => {
|
||||
let t: ty::t = fcx.infcx().next_ty_var();
|
||||
check_expr_has_type(fcx, &**element, t);
|
||||
(fcx.expr_ty(&**element), t)
|
||||
}
|
||||
};
|
||||
|
||||
if ty::type_is_error(element_ty) {
|
||||
fcx.write_error(id);
|
||||
}
|
||||
else if ty::type_is_bot(element_ty) {
|
||||
} else if ty::type_is_bot(element_ty) {
|
||||
fcx.write_bot(id);
|
||||
}
|
||||
else {
|
||||
let t = ty::mk_vec(tcx, ty::mt {ty: t, mutbl: ast::MutImmutable},
|
||||
Some(count));
|
||||
} else {
|
||||
let t = ty::mk_vec(tcx, t, Some(count));
|
||||
fcx.write_ty(id, t);
|
||||
}
|
||||
}
|
||||
@ -3585,12 +3538,17 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
let mut err_field = false;
|
||||
|
||||
let elt_ts = elts.iter().enumerate().map(|(i, e)| {
|
||||
let opt_hint = match flds {
|
||||
Some(ref fs) if i < fs.len() => ExpectHasType(*fs.get(i)),
|
||||
_ => NoExpectation
|
||||
let t = match flds {
|
||||
Some(ref fs) if i < fs.len() => {
|
||||
let ety = *fs.get(i);
|
||||
check_expr_coercable_to_type(fcx, &**e, ety);
|
||||
ety
|
||||
}
|
||||
_ => {
|
||||
check_expr_with_expectation(fcx, &**e, NoExpectation);
|
||||
fcx.expr_ty(&**e)
|
||||
}
|
||||
};
|
||||
check_expr_with_expectation(fcx, &**e, opt_hint);
|
||||
let t = fcx.expr_ty(&**e);
|
||||
err_field = err_field || ty::type_is_error(t);
|
||||
bot_field = bot_field || ty::type_is_bot(t);
|
||||
t
|
||||
@ -3702,9 +3660,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt,
|
||||
autoderef(fcx, expr.span, raw_base_t, Some(base.id),
|
||||
lvalue_pref, |base_t, _| ty::index(base_t));
|
||||
match field_ty {
|
||||
Some(mt) => {
|
||||
Some(ty) => {
|
||||
check_expr_has_type(fcx, &**idx, ty::mk_uint());
|
||||
fcx.write_ty(id, mt.ty);
|
||||
fcx.write_ty(id, ty);
|
||||
fcx.write_autoderef_adjustment(base.id, autoderefs);
|
||||
}
|
||||
None => {
|
||||
@ -3967,34 +3925,42 @@ fn check_block_with_expected(fcx: &FnCtxt,
|
||||
}
|
||||
match blk.expr {
|
||||
None => if any_err {
|
||||
fcx.write_error(blk.id);
|
||||
fcx.write_error(blk.id);
|
||||
}
|
||||
else if any_bot {
|
||||
fcx.write_bot(blk.id);
|
||||
}
|
||||
else {
|
||||
fcx.write_nil(blk.id);
|
||||
},
|
||||
Some(e) => {
|
||||
if any_bot && !warned {
|
||||
fcx.ccx
|
||||
.tcx
|
||||
.sess
|
||||
.add_lint(lint::builtin::UNREACHABLE_CODE,
|
||||
e.id,
|
||||
e.span,
|
||||
"unreachable expression".to_string());
|
||||
}
|
||||
let ety = match expected {
|
||||
ExpectHasType(ety) => {
|
||||
check_expr_coercable_to_type(fcx, &*e, ety);
|
||||
ety
|
||||
}
|
||||
_ => {
|
||||
check_expr_with_expectation(fcx, &*e, expected);
|
||||
fcx.expr_ty(&*e)
|
||||
}
|
||||
};
|
||||
|
||||
fcx.write_ty(blk.id, ety);
|
||||
if any_err {
|
||||
fcx.write_error(blk.id);
|
||||
} else if any_bot {
|
||||
fcx.write_bot(blk.id);
|
||||
}
|
||||
}
|
||||
else if any_bot {
|
||||
fcx.write_bot(blk.id);
|
||||
}
|
||||
else {
|
||||
fcx.write_nil(blk.id);
|
||||
},
|
||||
Some(e) => {
|
||||
if any_bot && !warned {
|
||||
fcx.ccx
|
||||
.tcx
|
||||
.sess
|
||||
.add_lint(lint::builtin::UNREACHABLE_CODE,
|
||||
e.id,
|
||||
e.span,
|
||||
"unreachable expression".to_string());
|
||||
}
|
||||
check_expr_with_expectation(fcx, &*e, expected);
|
||||
let ety = fcx.expr_ty(&*e);
|
||||
fcx.write_ty(blk.id, ety);
|
||||
if any_err {
|
||||
fcx.write_error(blk.id);
|
||||
}
|
||||
else if any_bot {
|
||||
fcx.write_bot(blk.id);
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
@ -4040,9 +4006,8 @@ pub fn check_const_with_ty(fcx: &FnCtxt,
|
||||
// emit a error.
|
||||
GatherLocalsVisitor { fcx: fcx }.visit_expr(e, ());
|
||||
|
||||
check_expr(fcx, e);
|
||||
let cty = fcx.expr_ty(e);
|
||||
demand::suptype(fcx, e.span, declty, cty);
|
||||
check_expr_with_hint(fcx, e, declty);
|
||||
demand::coerce(fcx, e.span, declty, e);
|
||||
regionck::regionck_expr(fcx, e);
|
||||
writeback::resolve_type_vars_in_expr(fcx, e);
|
||||
}
|
||||
@ -4132,6 +4097,7 @@ pub fn check_simd(tcx: &ty::ctxt, sp: Span, id: ast::NodeId) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn check_enum_variants_sized(ccx: &CrateCtxt,
|
||||
vs: &[ast::P<ast::Variant>]) {
|
||||
for &v in vs.iter() {
|
||||
@ -4747,39 +4713,39 @@ pub fn type_is_uint(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
return ty::type_is_uint(typ_s);
|
||||
}
|
||||
|
||||
pub fn ast_expr_vstore_to_ty(fcx: &FnCtxt,
|
||||
e: &ast::Expr,
|
||||
v: ast::ExprVstore,
|
||||
mk_inner: || -> ty::mt)
|
||||
-> ty::t {
|
||||
match v {
|
||||
ast::ExprVstoreUniq => ty::mk_uniq(fcx.ccx.tcx, mk_inner().ty),
|
||||
ast::ExprVstoreSlice | ast::ExprVstoreMutSlice => {
|
||||
match e.node {
|
||||
ast::ExprLit(..) => {
|
||||
// string literals and *empty slices* live in static memory
|
||||
ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner())
|
||||
}
|
||||
ast::ExprVec(ref elements) if elements.len() == 0 => {
|
||||
// string literals and *empty slices* live in static memory
|
||||
ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner())
|
||||
}
|
||||
ast::ExprRepeat(..) |
|
||||
ast::ExprVec(..) => {
|
||||
// vector literals are temporaries on the stack
|
||||
match fcx.tcx().region_maps.temporary_scope(e.id) {
|
||||
Some(scope) => ty::mk_rptr(fcx.ccx.tcx, ty::ReScope(scope), mk_inner()),
|
||||
None => ty::mk_rptr(fcx.ccx.tcx, ty::ReStatic, mk_inner()),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
fcx.ccx.tcx.sess.span_bug(e.span,
|
||||
"vstore with unexpected \
|
||||
contents")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn type_is_scalar(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_scalar(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_char(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_char(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_bare_fn(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_bare_fn(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_floating_point(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_floating_point(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_unsafe_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_unsafe_ptr(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_region_ptr(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_region_ptr(typ_s);
|
||||
}
|
||||
|
||||
pub fn type_is_c_like_enum(fcx: &FnCtxt, sp: Span, typ: ty::t) -> bool {
|
||||
let typ_s = structurally_resolved_type(fcx, sp, typ);
|
||||
return ty::type_is_c_like_enum(fcx.ccx.tcx, typ_s);
|
||||
}
|
||||
|
||||
// Returns true if b contains a break that can exit from b
|
||||
|
@ -413,40 +413,43 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
|
||||
for &adjustment in rcx.fcx.inh.adjustments.borrow().find(&expr.id).iter() {
|
||||
debug!("adjustment={:?}", adjustment);
|
||||
match *adjustment {
|
||||
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: opt_autoref}) => {
|
||||
ty::AutoDerefRef(ty::AutoDerefRef {autoderefs, autoref: ref opt_autoref}) => {
|
||||
let expr_ty = rcx.resolve_node_type(expr.id);
|
||||
constrain_autoderefs(rcx, expr, autoderefs, expr_ty);
|
||||
for autoref in opt_autoref.iter() {
|
||||
link_autoref(rcx, expr, autoderefs, autoref);
|
||||
match ty::adjusted_object_region(adjustment) {
|
||||
Some(trait_region) => {
|
||||
// Determine if we are casting `expr` to a trait
|
||||
// instance. If so, we have to be sure that the type of
|
||||
// the source obeys the trait's region bound.
|
||||
//
|
||||
// Note: there is a subtle point here concerning type
|
||||
// parameters. It is possible that the type of `source`
|
||||
// contains type parameters, which in turn may contain
|
||||
// regions that are not visible to us (only the caller
|
||||
// knows about them). The kind checker is ultimately
|
||||
// responsible for guaranteeing region safety in that
|
||||
// particular case. There is an extensive comment on the
|
||||
// function check_cast_for_escaping_regions() in kind.rs
|
||||
// explaining how it goes about doing that.
|
||||
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, expr.id, ty::ReScope(expr.id),
|
||||
infer::AutoBorrow(expr.span));
|
||||
constrain_regions_in_type(rcx, trait_region,
|
||||
infer::RelateObjectBound(expr.span), expr_ty);
|
||||
}
|
||||
None => {
|
||||
for autoref in opt_autoref.iter() {
|
||||
link_autoref(rcx, expr, autoderefs, autoref);
|
||||
|
||||
// Require that the resulting region encompasses
|
||||
// the current node.
|
||||
//
|
||||
// FIXME(#6268) remove to support nested method calls
|
||||
constrain_regions_in_type_of_node(
|
||||
rcx, expr.id, ty::ReScope(expr.id),
|
||||
infer::AutoBorrow(expr.span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ty::AutoObject(ty::RegionTraitStore(trait_region, _), _, _, _) => {
|
||||
// Determine if we are casting `expr` to a trait
|
||||
// instance. If so, we have to be sure that the type of
|
||||
// the source obeys the trait's region bound.
|
||||
//
|
||||
// Note: there is a subtle point here concerning type
|
||||
// parameters. It is possible that the type of `source`
|
||||
// contains type parameters, which in turn may contain
|
||||
// regions that are not visible to us (only the caller
|
||||
// knows about them). The kind checker is ultimately
|
||||
// responsible for guaranteeing region safety in that
|
||||
// particular case. There is an extensive comment on the
|
||||
// function check_cast_for_escaping_regions() in kind.rs
|
||||
// explaining how it goes about doing that.
|
||||
|
||||
let source_ty = rcx.resolve_node_type(expr.id);
|
||||
constrain_regions_in_type(rcx, trait_region,
|
||||
infer::RelateObjectBound(expr.span), source_ty);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@ -1176,24 +1179,12 @@ fn link_autoref(rcx: &Rcx,
|
||||
debug!("expr_cmt={}", expr_cmt.repr(rcx.tcx()));
|
||||
|
||||
match *autoref {
|
||||
ty::AutoPtr(r, m) => {
|
||||
ty::AutoPtr(r, m, _) => {
|
||||
link_region(rcx, expr.span, r,
|
||||
ty::BorrowKind::from_mutbl(m), expr_cmt);
|
||||
ty::BorrowKind::from_mutbl(m), expr_cmt);
|
||||
}
|
||||
|
||||
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
|
||||
let cmt_index = mc.cat_index(expr, expr_cmt, autoderefs+1);
|
||||
link_region(rcx, expr.span, r,
|
||||
ty::BorrowKind::from_mutbl(m), cmt_index);
|
||||
}
|
||||
|
||||
ty::AutoBorrowObj(r, m) => {
|
||||
let cmt_deref = mc.cat_deref_obj(expr, expr_cmt);
|
||||
link_region(rcx, expr.span, r,
|
||||
ty::BorrowKind::from_mutbl(m), cmt_deref);
|
||||
}
|
||||
|
||||
ty::AutoUnsafe(_) => {}
|
||||
ty::AutoUnsafe(_) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
|
||||
use middle::ty;
|
||||
use middle::ty::{AutoAddEnv, AutoDerefRef, AutoObject, ParamTy};
|
||||
use middle::ty::{AutoDerefRef, ParamTy};
|
||||
use middle::ty_fold::TypeFolder;
|
||||
use middle::typeck::astconv::AstConv;
|
||||
use middle::typeck::check::{FnCtxt, impl_self_ty};
|
||||
@ -388,7 +388,6 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||
trait_ref: Rc<ty::TraitRef>,
|
||||
is_early: bool)
|
||||
-> Option<vtable_origin> {
|
||||
debug!("nrc - search_for_vtable");
|
||||
let tcx = vcx.tcx();
|
||||
|
||||
// First, check to see whether this is a call to the `call` method of an
|
||||
@ -630,14 +629,8 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
let _indent = indenter();
|
||||
|
||||
let cx = fcx.ccx;
|
||||
let resolve_object_cast = |src: &ast::Expr, target_ty: ty::t, key: MethodCall| {
|
||||
// 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>`
|
||||
// Bounds of type's contents are not checked here, but in kind.rs.
|
||||
let src_ty = structurally_resolved_type(fcx, ex.span,
|
||||
fcx.expr_ty(src));
|
||||
let check_object_cast = |src_ty: ty::t, target_ty: ty::t| {
|
||||
// Check that a cast is of correct types.
|
||||
match (&ty::get(target_ty).sty, &ty::get(src_ty).sty) {
|
||||
(&ty::ty_rptr(_, ty::mt{ty, mutbl}), &ty::ty_rptr(_, mt))
|
||||
if !mutability_allowed(mt.mutbl, mutbl) => {
|
||||
@ -648,74 +641,14 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
(&ty::ty_uniq(ty), &ty::ty_uniq(..) ) |
|
||||
(&ty::ty_rptr(_, ty::mt{ty, ..}), &ty::ty_rptr(..)) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_trait(box ty::TyTrait {
|
||||
def_id: target_def_id, substs: ref target_substs, ..
|
||||
}) => {
|
||||
debug!("nrc correct path");
|
||||
let typ = match &ty::get(src_ty).sty {
|
||||
&ty::ty_uniq(typ) => typ,
|
||||
&ty::ty_rptr(_, mt) => mt.ty,
|
||||
_ => fail!("shouldn't get here"),
|
||||
};
|
||||
|
||||
let vcx = fcx.vtable_context();
|
||||
|
||||
// Take the type parameters from the object
|
||||
// type, but set the Self type (which is
|
||||
// unknown, for the object type) to be the type
|
||||
// we are casting from.
|
||||
let mut target_types = target_substs.types.clone();
|
||||
assert!(target_types.get_self().is_none());
|
||||
target_types.push(subst::SelfSpace, typ);
|
||||
|
||||
let target_trait_ref = Rc::new(ty::TraitRef {
|
||||
def_id: target_def_id,
|
||||
substs: subst::Substs {
|
||||
regions: target_substs.regions.clone(),
|
||||
types: target_types
|
||||
}
|
||||
});
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::empty_builtin_bounds(),
|
||||
trait_bounds: vec!(target_trait_ref)
|
||||
};
|
||||
let vtables =
|
||||
lookup_vtables_for_param(&vcx,
|
||||
ex.span,
|
||||
None,
|
||||
¶m_bounds,
|
||||
typ,
|
||||
is_early);
|
||||
|
||||
if !is_early {
|
||||
let mut r = VecPerParamSpace::empty();
|
||||
r.push(subst::SelfSpace, vtables);
|
||||
insert_vtables(fcx, key, r);
|
||||
}
|
||||
|
||||
// Now, if this is &trait, we need to link the
|
||||
// regions.
|
||||
match (&ty::get(src_ty).sty, &ty::get(target_ty).sty) {
|
||||
(&ty::ty_rptr(ra, _), &ty::ty_rptr(rb, _)) => {
|
||||
debug!("nrc - make subr");
|
||||
infer::mk_subr(fcx.infcx(),
|
||||
false,
|
||||
infer::RelateObjectBound(ex.span),
|
||||
rb,
|
||||
ra);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
(&ty::ty_uniq(..), &ty::ty_uniq(..) ) => {}
|
||||
(&ty::ty_rptr(r_t, _), &ty::ty_rptr(r_s, _)) => {
|
||||
infer::mk_subr(fcx.infcx(),
|
||||
false,
|
||||
infer::RelateObjectBound(ex.span),
|
||||
r_t,
|
||||
r_s);
|
||||
}
|
||||
|
||||
(&ty::ty_uniq(ty), _) => {
|
||||
match ty::get(ty).sty {
|
||||
ty::ty_trait(..) => {
|
||||
@ -737,7 +670,55 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
let resolve_object_cast = |src_ty: ty::t, target_ty: ty::t, key: MethodCall| {
|
||||
// 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>`
|
||||
// Bounds of type's contents are not checked here, but in kind.rs.
|
||||
match ty::get(target_ty).sty {
|
||||
ty::ty_trait(box ty::TyTrait {
|
||||
def_id: target_def_id, substs: ref target_substs, ..
|
||||
}) => {
|
||||
let vcx = fcx.vtable_context();
|
||||
|
||||
// Take the type parameters from the object
|
||||
// type, but set the Self type (which is
|
||||
// unknown, for the object type) to be the type
|
||||
// we are casting from.
|
||||
let mut target_types = target_substs.types.clone();
|
||||
assert!(target_types.get_self().is_none());
|
||||
target_types.push(subst::SelfSpace, src_ty);
|
||||
|
||||
let target_trait_ref = Rc::new(ty::TraitRef {
|
||||
def_id: target_def_id,
|
||||
substs: subst::Substs {
|
||||
regions: target_substs.regions.clone(),
|
||||
types: target_types
|
||||
}
|
||||
});
|
||||
|
||||
let param_bounds = ty::ParamBounds {
|
||||
builtin_bounds: ty::empty_builtin_bounds(),
|
||||
trait_bounds: vec!(target_trait_ref)
|
||||
};
|
||||
let vtables =
|
||||
lookup_vtables_for_param(&vcx,
|
||||
ex.span,
|
||||
None,
|
||||
¶m_bounds,
|
||||
src_ty,
|
||||
is_early);
|
||||
|
||||
if !is_early {
|
||||
let mut r = VecPerParamSpace::empty();
|
||||
r.push(subst::SelfSpace, vtables);
|
||||
insert_vtables(fcx, key, r);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
@ -792,8 +773,16 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
ast::ExprCast(ref src, _) => {
|
||||
debug!("vtable resolution on expr {}", ex.repr(fcx.tcx()));
|
||||
let target_ty = fcx.expr_ty(ex);
|
||||
let key = MethodCall::expr(ex.id);
|
||||
resolve_object_cast(&**src, target_ty, key);
|
||||
let src_ty = structurally_resolved_type(fcx, ex.span,
|
||||
fcx.expr_ty(&**src));
|
||||
check_object_cast(src_ty, target_ty);
|
||||
match (ty::deref(src_ty, false), ty::deref(target_ty, false)) {
|
||||
(Some(s), Some(t)) => {
|
||||
let key = MethodCall::expr(ex.id);
|
||||
resolve_object_cast(s.ty, t.ty, key)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => ()
|
||||
}
|
||||
@ -802,7 +791,25 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
match fcx.inh.adjustments.borrow().find(&ex.id) {
|
||||
Some(adjustment) => {
|
||||
match *adjustment {
|
||||
AutoDerefRef(adj) => {
|
||||
_ if ty::adjust_is_object(adjustment) => {
|
||||
let src_ty = structurally_resolved_type(fcx, ex.span,
|
||||
fcx.expr_ty(ex));
|
||||
match ty::type_of_adjust(fcx.tcx(), adjustment) {
|
||||
Some(target_ty) => {
|
||||
check_object_cast(src_ty, target_ty)
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
match trait_cast_types(fcx, adjustment, src_ty, ex.span) {
|
||||
Some((s, t)) => {
|
||||
let key = MethodCall::autoobject(ex.id);
|
||||
resolve_object_cast(s, t, key)
|
||||
}
|
||||
None => fail!("Couldn't extract types from adjustment")
|
||||
}
|
||||
}
|
||||
AutoDerefRef(ref adj) => {
|
||||
for autoderef in range(0, adj.autoderefs) {
|
||||
let method_call = MethodCall::autoderef(ex.id, autoderef);
|
||||
match fcx.inh.method_map.borrow().find(&method_call) {
|
||||
@ -823,37 +830,75 @@ pub fn early_resolve_expr(ex: &ast::Expr, fcx: &FnCtxt, is_early: bool) {
|
||||
}
|
||||
}
|
||||
}
|
||||
AutoObject(store,
|
||||
bounds,
|
||||
def_id,
|
||||
ref substs) => {
|
||||
debug!("doing trait adjustment for expr {} {} \
|
||||
(early? {})",
|
||||
ex.id,
|
||||
ex.repr(fcx.tcx()),
|
||||
is_early);
|
||||
|
||||
let trait_ty = ty::mk_trait(cx.tcx,
|
||||
def_id,
|
||||
substs.clone(),
|
||||
bounds);
|
||||
let object_ty = match store {
|
||||
ty::UniqTraitStore => ty::mk_uniq(cx.tcx, trait_ty),
|
||||
ty::RegionTraitStore(r, m) => {
|
||||
ty::mk_rptr(cx.tcx, r, ty::mt {ty: trait_ty, mutbl: m})
|
||||
}
|
||||
};
|
||||
|
||||
let key = MethodCall::autoobject(ex.id);
|
||||
resolve_object_cast(ex, object_ty, key);
|
||||
}
|
||||
AutoAddEnv(..) => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
// When we coerce (possibly implicitly) from a concrete type to a trait type, this
|
||||
// function returns the concrete type and trait. This might happen arbitrarily
|
||||
// deep in the adjustment. This function will fail if the adjustment does not
|
||||
// match the source type.
|
||||
// This function will always return types if ty::adjust_is_object is true for the
|
||||
// adjustment
|
||||
fn trait_cast_types(fcx: &FnCtxt,
|
||||
adj: &ty::AutoAdjustment,
|
||||
src_ty: ty::t,
|
||||
sp: Span)
|
||||
-> Option<(ty::t, ty::t)> {
|
||||
fn trait_cast_types_autoref(fcx: &FnCtxt,
|
||||
autoref: &ty::AutoRef,
|
||||
src_ty: ty::t,
|
||||
sp: Span)
|
||||
-> Option<(ty::t, ty::t)> {
|
||||
fn trait_cast_types_unsize(fcx: &FnCtxt,
|
||||
k: &ty::UnsizeKind,
|
||||
src_ty: ty::t,
|
||||
sp: Span)
|
||||
-> Option<(ty::t, ty::t)> {
|
||||
match k {
|
||||
&ty::UnsizeVtable(bounds, def_id, ref substs) => {
|
||||
Some((src_ty, ty::mk_trait(fcx.tcx(), def_id, substs.clone(), bounds)))
|
||||
}
|
||||
&ty::UnsizeStruct(box ref k, tp_index) => match ty::get(src_ty).sty {
|
||||
ty::ty_struct(_, ref substs) => {
|
||||
let ty_substs = substs.types.get_slice(subst::TypeSpace);
|
||||
let field_ty = structurally_resolved_type(fcx, sp, ty_substs[tp_index]);
|
||||
trait_cast_types_unsize(fcx, k, field_ty, sp)
|
||||
}
|
||||
_ => fail!("Failed to find a ty_struct to correspond with \
|
||||
UnsizeStruct whilst walking adjustment. Found {}",
|
||||
ppaux::ty_to_string(fcx.tcx(), src_ty))
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
match autoref {
|
||||
&ty::AutoUnsize(ref k) |
|
||||
&ty::AutoUnsizeUniq(ref k) => trait_cast_types_unsize(fcx, k, src_ty, sp),
|
||||
&ty::AutoPtr(_, _, Some(box ref autoref)) => {
|
||||
trait_cast_types_autoref(fcx, autoref, src_ty, sp)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
match adj {
|
||||
&ty::AutoDerefRef(AutoDerefRef{autoref: Some(ref autoref), autoderefs}) => {
|
||||
let mut derefed_type = src_ty;
|
||||
for _ in range(0, autoderefs) {
|
||||
derefed_type = ty::deref(derefed_type, false).unwrap().ty;
|
||||
derefed_type = structurally_resolved_type(fcx, sp, derefed_type)
|
||||
}
|
||||
trait_cast_types_autoref(fcx, autoref, derefed_type, sp)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolve_impl(tcx: &ty::ctxt,
|
||||
impl_item: &ast::Item,
|
||||
impl_generics: &ty::Generics,
|
||||
|
@ -259,6 +259,7 @@ impl<'cx> WritebackCx<'cx> {
|
||||
}
|
||||
|
||||
Some(adjustment) => {
|
||||
let adj_object = ty::adjust_is_object(&adjustment);
|
||||
let resolved_adjustment = match adjustment {
|
||||
ty::AutoAddEnv(store) => {
|
||||
// FIXME(eddyb) #2190 Allow only statically resolved
|
||||
@ -286,24 +287,17 @@ impl<'cx> WritebackCx<'cx> {
|
||||
self.visit_vtable_map_entry(reason, method_call);
|
||||
}
|
||||
|
||||
if adj_object {
|
||||
let method_call = MethodCall::autoobject(id);
|
||||
self.visit_method_map_entry(reason, method_call);
|
||||
self.visit_vtable_map_entry(reason, method_call);
|
||||
}
|
||||
|
||||
ty::AutoDerefRef(ty::AutoDerefRef {
|
||||
autoderefs: adj.autoderefs,
|
||||
autoref: self.resolve(&adj.autoref, reason),
|
||||
})
|
||||
}
|
||||
|
||||
ty::AutoObject(trait_store, bb, def_id, substs) => {
|
||||
let method_call = MethodCall::autoobject(id);
|
||||
self.visit_method_map_entry(reason, method_call);
|
||||
self.visit_vtable_map_entry(reason, method_call);
|
||||
|
||||
ty::AutoObject(
|
||||
self.resolve(&trait_store, reason),
|
||||
self.resolve(&bb, reason),
|
||||
def_id,
|
||||
self.resolve(&substs, reason)
|
||||
)
|
||||
}
|
||||
};
|
||||
debug!("Adjustments for node {}: {:?}", id, resolved_adjustment);
|
||||
self.tcx().adjustments.borrow_mut().insert(
|
||||
|
@ -23,7 +23,7 @@ use middle::ty::get;
|
||||
use middle::ty::{ImplContainer, ImplOrTraitItemId, MethodTraitItemId};
|
||||
use middle::ty::{lookup_item_type};
|
||||
use middle::ty::{t, ty_bool, ty_char, ty_bot, ty_box, ty_enum, ty_err};
|
||||
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil};
|
||||
use middle::ty::{ty_str, ty_vec, ty_float, ty_infer, ty_int, ty_nil, ty_open};
|
||||
use middle::ty::{ty_param, Polytype, ty_ptr};
|
||||
use middle::ty::{ty_rptr, ty_struct, ty_trait, ty_tup};
|
||||
use middle::ty::{ty_uint, ty_unboxed_closure, ty_uniq, ty_bare_fn};
|
||||
@ -86,7 +86,7 @@ fn get_base_type(inference_context: &InferCtxt,
|
||||
|
||||
ty_nil | ty_bot | ty_bool | ty_char | ty_int(..) | ty_uint(..) | ty_float(..) |
|
||||
ty_str(..) | ty_vec(..) | ty_bare_fn(..) | ty_closure(..) | ty_tup(..) |
|
||||
ty_infer(..) | ty_param(..) | ty_err |
|
||||
ty_infer(..) | ty_param(..) | ty_err | ty_open(..) |
|
||||
ty_box(_) | ty_uniq(_) | ty_ptr(_) | ty_rptr(_, _) => {
|
||||
debug!("(getting base type) no base type; found {:?}",
|
||||
get(original_type).sty);
|
||||
@ -166,6 +166,9 @@ fn get_base_type_def_id(inference_context: &InferCtxt,
|
||||
enum, struct, or trait");
|
||||
}
|
||||
},
|
||||
ty_trait(box ty::TyTrait { def_id, .. }) => {
|
||||
Some(def_id)
|
||||
}
|
||||
_ => {
|
||||
fail!("get_base_type() returned a type that wasn't an \
|
||||
enum, struct, or trait");
|
||||
|
@ -65,7 +65,7 @@ we may want to adjust precisely when coercions occur.
|
||||
*/
|
||||
|
||||
use middle::subst;
|
||||
use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowObj, AutoDerefRef};
|
||||
use middle::ty::{AutoPtr, AutoDerefRef, AutoUnsize};
|
||||
use middle::ty::{mt};
|
||||
use middle::ty;
|
||||
use middle::typeck::infer::{CoerceResult, resolve_type, Coercion};
|
||||
@ -73,6 +73,7 @@ use middle::typeck::infer::combine::{CombineFields, Combine};
|
||||
use middle::typeck::infer::sub::Sub;
|
||||
use middle::typeck::infer::resolve::try_resolve_tvar_shallow;
|
||||
use util::common::indenter;
|
||||
use util::ppaux;
|
||||
use util::ppaux::Repr;
|
||||
|
||||
use syntax::abi;
|
||||
@ -94,38 +95,51 @@ impl<'f> Coerce<'f> {
|
||||
b.repr(self.get_ref().infcx.tcx));
|
||||
let _indent = indenter();
|
||||
|
||||
// Special case: if the subtype is a sized array literal (`[T, ..n]`),
|
||||
// then it would get auto-borrowed to `&[T, ..n]` and then DST-ified
|
||||
// to `&[T]`. Doing it all at once makes the target code a bit more
|
||||
// efficient and spares us from having to handle multiple coercions.
|
||||
match ty::get(b).sty {
|
||||
ty::ty_rptr(_, mt_b) => {
|
||||
match ty::get(mt_b.ty).sty {
|
||||
ty::ty_vec(_, None) => {
|
||||
let unsize_and_ref = self.unpack_actual_value(a, |sty_a| {
|
||||
self.coerce_unsized_with_borrow(a, sty_a, b, mt_b.mutbl)
|
||||
});
|
||||
if unsize_and_ref.is_ok() {
|
||||
return unsize_and_ref;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Consider coercing the subtype to a DST
|
||||
let unsize = self.unpack_actual_value(a, |sty_a| {
|
||||
self.coerce_unsized(a, sty_a, b)
|
||||
});
|
||||
if unsize.is_ok() {
|
||||
return unsize;
|
||||
}
|
||||
|
||||
// Examine the supertype and consider auto-borrowing.
|
||||
//
|
||||
// Note: does not attempt to resolve type variables we encounter.
|
||||
// See above for details.
|
||||
match ty::get(b).sty {
|
||||
ty::ty_rptr(r_b, mt_b) => {
|
||||
ty::ty_rptr(_, mt_b) => {
|
||||
match ty::get(mt_b.ty).sty {
|
||||
ty::ty_vec(mt_b, None) => {
|
||||
return self.unpack_actual_value(a, |sty_a| {
|
||||
self.coerce_borrowed_vector(a, sty_a, b, mt_b.mutbl)
|
||||
});
|
||||
}
|
||||
ty::ty_vec(_, _) => {},
|
||||
ty::ty_str => {
|
||||
return self.unpack_actual_value(a, |sty_a| {
|
||||
self.coerce_borrowed_string(a, sty_a, b)
|
||||
self.coerce_borrowed_pointer(a, sty_a, b, ast::MutImmutable)
|
||||
});
|
||||
}
|
||||
|
||||
ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
|
||||
ty::ty_trait(..) => {
|
||||
let result = self.unpack_actual_value(a, |sty_a| {
|
||||
match *sty_a {
|
||||
ty::ty_rptr(_, mt_a) => match ty::get(mt_a.ty).sty {
|
||||
ty::ty_trait(..) => {
|
||||
self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
|
||||
}
|
||||
_ => self.coerce_object(a, sty_a, b, def_id, substs,
|
||||
ty::RegionTraitStore(r_b, mt_b.mutbl),
|
||||
bounds)
|
||||
},
|
||||
_ => self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
|
||||
}
|
||||
self.coerce_borrowed_object(a, sty_a, b, mt_b.mutbl)
|
||||
});
|
||||
|
||||
match result {
|
||||
@ -136,37 +150,12 @@ impl<'f> Coerce<'f> {
|
||||
|
||||
_ => {
|
||||
return self.unpack_actual_value(a, |sty_a| {
|
||||
self.coerce_borrowed_pointer(a, sty_a, b, mt_b)
|
||||
self.coerce_borrowed_pointer(a, sty_a, b, mt_b.mutbl)
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
ty::ty_uniq(t_b) => {
|
||||
match ty::get(t_b).sty {
|
||||
ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds }) => {
|
||||
let result = self.unpack_actual_value(a, |sty_a| {
|
||||
match *sty_a {
|
||||
ty::ty_uniq(t_a) => match ty::get(t_a).sty {
|
||||
ty::ty_trait(..) => {
|
||||
Err(ty::terr_mismatch)
|
||||
}
|
||||
_ => self.coerce_object(a, sty_a, b, def_id, substs,
|
||||
ty::UniqTraitStore, bounds)
|
||||
},
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
});
|
||||
|
||||
match result {
|
||||
Ok(t) => return Ok(t),
|
||||
Err(..) => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
ty::ty_closure(box ty::ClosureTy {
|
||||
store: ty::RegionTraitStore(..),
|
||||
..
|
||||
@ -210,8 +199,8 @@ impl<'f> Coerce<'f> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unpack_actual_value(&self, a: ty::t, f: |&ty::sty| -> CoerceResult)
|
||||
-> CoerceResult {
|
||||
pub fn unpack_actual_value<T>(&self, a: ty::t, f: |&ty::sty| -> T)
|
||||
-> T {
|
||||
match resolve_type(self.get_ref().infcx, None,
|
||||
a, try_resolve_tvar_shallow) {
|
||||
Ok(t) => {
|
||||
@ -221,20 +210,21 @@ impl<'f> Coerce<'f> {
|
||||
self.get_ref().infcx.tcx.sess.span_bug(
|
||||
self.get_ref().trace.origin.span(),
|
||||
format!("failed to resolve even without \
|
||||
any force options: {:?}", e).as_slice());
|
||||
any force options: {:?}", e).as_slice());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ~T -> &T or &mut T -> &T (including where T = [U] or str)
|
||||
pub fn coerce_borrowed_pointer(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t,
|
||||
mt_b: ty::mt)
|
||||
mutbl_b: ast::Mutability)
|
||||
-> CoerceResult {
|
||||
debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={}, mt_b={:?})",
|
||||
debug!("coerce_borrowed_pointer(a={}, sty_a={:?}, b={})",
|
||||
a.repr(self.get_ref().infcx.tcx), sty_a,
|
||||
b.repr(self.get_ref().infcx.tcx), mt_b);
|
||||
b.repr(self.get_ref().infcx.tcx));
|
||||
|
||||
// If we have a parameter of type `&M T_a` and the value
|
||||
// provided is `expr`, we will be adding an implicit borrow,
|
||||
@ -256,64 +246,182 @@ impl<'f> Coerce<'f> {
|
||||
|
||||
let a_borrowed = ty::mk_rptr(self.get_ref().infcx.tcx,
|
||||
r_borrow,
|
||||
mt {ty: inner_ty, mutbl: mt_b.mutbl});
|
||||
mt {ty: inner_ty, mutbl: mutbl_b});
|
||||
if_ok!(sub.tys(a_borrowed, b));
|
||||
|
||||
Ok(Some(AutoDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(AutoPtr(r_borrow, mt_b.mutbl))
|
||||
autoref: Some(AutoPtr(r_borrow, mutbl_b, None))
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn coerce_borrowed_string(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t)
|
||||
-> CoerceResult {
|
||||
debug!("coerce_borrowed_string(a={}, sty_a={:?}, b={})",
|
||||
a.repr(self.get_ref().infcx.tcx), sty_a,
|
||||
b.repr(self.get_ref().infcx.tcx));
|
||||
|
||||
match *sty_a {
|
||||
ty::ty_uniq(_) => return Err(ty::terr_mismatch),
|
||||
_ => return self.subtype(a, b),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn coerce_borrowed_vector(&self,
|
||||
// [T, ..n] -> &[T] or &mut [T]
|
||||
fn coerce_unsized_with_borrow(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t,
|
||||
mutbl_b: ast::Mutability)
|
||||
-> CoerceResult {
|
||||
debug!("coerce_borrowed_vector(a={}, sty_a={:?}, b={})",
|
||||
debug!("coerce_unsized_with_borrow(a={}, sty_a={:?}, b={})",
|
||||
a.repr(self.get_ref().infcx.tcx), sty_a,
|
||||
b.repr(self.get_ref().infcx.tcx));
|
||||
|
||||
let sub = Sub(self.get_ref().clone());
|
||||
let coercion = Coercion(self.get_ref().trace.clone());
|
||||
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
|
||||
let ty_inner = match *sty_a {
|
||||
ty::ty_uniq(_) => return Err(ty::terr_mismatch),
|
||||
ty::ty_ptr(ty::mt{ty: t, ..}) |
|
||||
ty::ty_rptr(_, ty::mt{ty: t, ..}) => match ty::get(t).sty {
|
||||
ty::ty_vec(mt, None) => mt.ty,
|
||||
_ => {
|
||||
return self.subtype(a, b);
|
||||
}
|
||||
},
|
||||
ty::ty_vec(mt, _) => mt.ty,
|
||||
_ => {
|
||||
return self.subtype(a, b);
|
||||
match *sty_a {
|
||||
ty::ty_vec(t_a, Some(len)) => {
|
||||
let sub = Sub(self.get_ref().clone());
|
||||
let coercion = Coercion(self.get_ref().trace.clone());
|
||||
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
|
||||
let unsized_ty = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
|
||||
mt {ty: t_a, mutbl: mutbl_b});
|
||||
if_ok!(self.get_ref().infcx.try(|| sub.tys(unsized_ty, b)));
|
||||
Ok(Some(AutoDerefRef(AutoDerefRef {
|
||||
autoderefs: 0,
|
||||
autoref: Some(ty::AutoPtr(r_borrow,
|
||||
mutbl_b,
|
||||
Some(box AutoUnsize(ty::UnsizeLength(len)))))
|
||||
})))
|
||||
}
|
||||
};
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
}
|
||||
|
||||
let a_borrowed = ty::mk_slice(self.get_ref().infcx.tcx, r_borrow,
|
||||
mt {ty: ty_inner, mutbl: mutbl_b});
|
||||
if_ok!(sub.tys(a_borrowed, b));
|
||||
Ok(Some(AutoDerefRef(AutoDerefRef {
|
||||
autoderefs: 0,
|
||||
autoref: Some(AutoBorrowVec(r_borrow, mutbl_b))
|
||||
})))
|
||||
// &[T, ..n] or &mut [T, ..n] -> &[T]
|
||||
// or &mut [T, ..n] -> &mut [T]
|
||||
// or &Concrete -> &Trait, etc.
|
||||
fn coerce_unsized(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t)
|
||||
-> CoerceResult {
|
||||
debug!("coerce_unsized(a={}, sty_a={:?}, b={})",
|
||||
a.repr(self.get_ref().infcx.tcx), sty_a,
|
||||
b.repr(self.get_ref().infcx.tcx));
|
||||
|
||||
// Note, we want to avoid unnecessary unsizing. We don't want to coerce to
|
||||
// a DST unless we have to. This currently comes out in the wash since
|
||||
// we can't unify [T] with U. But to properly support DST, we need to allow
|
||||
// that, at which point we will need extra checks on b here.
|
||||
|
||||
let sub = Sub(self.get_ref().clone());
|
||||
|
||||
let sty_b = &ty::get(b).sty;
|
||||
match (sty_a, sty_b) {
|
||||
(&ty::ty_uniq(_), &ty::ty_rptr(..)) => Err(ty::terr_mismatch),
|
||||
(&ty::ty_rptr(_, ty::mt{ty: t_a, ..}), &ty::ty_rptr(_, mt_b)) => {
|
||||
self.unpack_actual_value(t_a, |sty_a| {
|
||||
match self.unsize_ty(sty_a, mt_b.ty) {
|
||||
Some((ty, kind)) => {
|
||||
let coercion = Coercion(self.get_ref().trace.clone());
|
||||
let r_borrow = self.get_ref().infcx.next_region_var(coercion);
|
||||
let ty = ty::mk_rptr(self.get_ref().infcx.tcx,
|
||||
r_borrow,
|
||||
ty::mt{ty: ty, mutbl: mt_b.mutbl});
|
||||
if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoPtr(AutoUnsize({:?})))", kind);
|
||||
Ok(Some(AutoDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoPtr(r_borrow, 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, |sty_a| {
|
||||
match self.unsize_ty(sty_a, t_b) {
|
||||
Some((ty, kind)) => {
|
||||
let ty = ty::mk_uniq(self.get_ref().infcx.tcx, ty);
|
||||
if_ok!(self.get_ref().infcx.try(|| sub.tys(ty, b)));
|
||||
debug!("Success, coerced with AutoDerefRef(1, \
|
||||
AutoUnsizeUniq({:?}))", kind);
|
||||
Ok(Some(AutoDerefRef(AutoDerefRef {
|
||||
autoderefs: 1,
|
||||
autoref: Some(ty::AutoUnsizeUniq(kind))
|
||||
})))
|
||||
}
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
})
|
||||
}
|
||||
_ => Err(ty::terr_mismatch)
|
||||
}
|
||||
}
|
||||
|
||||
// Takes a type and returns an unsized version along with the adjustment
|
||||
// performed to unsize it.
|
||||
// E.g., `[T, ..n]` -> `([T], UnsizeLength(n))`
|
||||
fn unsize_ty(&self,
|
||||
sty_a: &ty::sty,
|
||||
ty_b: ty::t)
|
||||
-> Option<(ty::t, ty::UnsizeKind)> {
|
||||
debug!("unsize_ty(sty_a={:?}", sty_a);
|
||||
|
||||
let tcx = self.get_ref().infcx.tcx;
|
||||
|
||||
self.unpack_actual_value(ty_b, |sty_b|
|
||||
match (sty_a, sty_b) {
|
||||
(&ty::ty_vec(t_a, Some(len)), _) => {
|
||||
let ty = ty::mk_vec(tcx, t_a, None);
|
||||
Some((ty, ty::UnsizeLength(len)))
|
||||
}
|
||||
(&ty::ty_trait(..), &ty::ty_trait(..)) => None,
|
||||
(_, &ty::ty_trait(box ty::TyTrait { def_id, ref substs, bounds })) => {
|
||||
let ty = ty::mk_trait(tcx,
|
||||
def_id,
|
||||
substs.clone(),
|
||||
bounds);
|
||||
Some((ty, ty::UnsizeVtable(bounds,
|
||||
def_id,
|
||||
substs.clone())))
|
||||
}
|
||||
(&ty::ty_struct(did_a, ref substs_a), &ty::ty_struct(did_b, ref 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 sub = Sub(self.get_ref().clone());
|
||||
|
||||
let mut result = None;
|
||||
let mut tps = ty_substs_a.iter().zip(ty_substs_b.iter()).enumerate();
|
||||
for (i, (tp_a, tp_b)) in tps {
|
||||
if self.get_ref().infcx.try(|| sub.tys(*tp_a, *tp_b)).is_ok() {
|
||||
continue;
|
||||
}
|
||||
match self.unpack_actual_value(*tp_a, |tp| self.unsize_ty(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, new_substs);
|
||||
if self.get_ref().infcx.try(|| sub.tys(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;
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
fn coerce_borrowed_object(&self,
|
||||
@ -352,8 +460,8 @@ impl<'f> Coerce<'f> {
|
||||
|
||||
if_ok!(self.subtype(a_borrowed, b));
|
||||
Ok(Some(AutoDerefRef(AutoDerefRef {
|
||||
autoderefs: 0,
|
||||
autoref: Some(AutoBorrowObj(r_a, b_mutbl))
|
||||
autoderefs: 1,
|
||||
autoref: Some(AutoPtr(r_a, b_mutbl, None))
|
||||
})))
|
||||
}
|
||||
|
||||
@ -438,21 +546,4 @@ impl<'f> Coerce<'f> {
|
||||
autoref: Some(ty::AutoUnsafe(mt_b.mutbl))
|
||||
})))
|
||||
}
|
||||
|
||||
pub fn coerce_object(&self,
|
||||
a: ty::t,
|
||||
sty_a: &ty::sty,
|
||||
b: ty::t,
|
||||
trait_def_id: ast::DefId,
|
||||
trait_substs: &subst::Substs,
|
||||
trait_store: ty::TraitStore,
|
||||
bounds: ty::BuiltinBounds) -> CoerceResult {
|
||||
|
||||
debug!("coerce_object(a={}, sty_a={:?}, b={})",
|
||||
a.repr(self.get_ref().infcx.tcx), sty_a,
|
||||
b.repr(self.get_ref().infcx.tcx));
|
||||
|
||||
Ok(Some(ty::AutoObject(trait_store, bounds,
|
||||
trait_def_id, trait_substs.clone())))
|
||||
}
|
||||
}
|
||||
|
@ -529,10 +529,10 @@ pub fn super_tys<C:Combine>(this: &C, a: ty::t, b: ty::t) -> cres<ty::t> {
|
||||
check_ptr_to_unsized(this, a, b, a_mt.ty, b_mt.ty, ty::mk_rptr(tcx, r, mt))
|
||||
}
|
||||
|
||||
(&ty::ty_vec(ref a_mt, sz_a), &ty::ty_vec(ref b_mt, sz_b)) => {
|
||||
this.mts(a_mt, b_mt).and_then(|mt| {
|
||||
(&ty::ty_vec(a_t, sz_a), &ty::ty_vec(b_t, sz_b)) => {
|
||||
this.tys(a_t, b_t).and_then(|t| {
|
||||
if sz_a == sz_b {
|
||||
Ok(ty::mk_vec(tcx, mt, sz_a))
|
||||
Ok(ty::mk_vec(tcx, t, sz_a))
|
||||
} else {
|
||||
Err(ty::terr_sorts(expected_found(this, a, b)))
|
||||
}
|
||||
|
@ -1411,8 +1411,8 @@ impl<'a> ErrorReportingHelpers for InferCtxt<'a> {
|
||||
infer::AutoBorrow(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
span,
|
||||
"...so that automatically reference is valid \
|
||||
at the time of borrow");
|
||||
"...so that reference is valid \
|
||||
at the time of implicit borrow");
|
||||
}
|
||||
infer::BindingTypeIsNotValidAtDecl(span) => {
|
||||
self.tcx.sess.span_note(
|
||||
|
@ -129,10 +129,23 @@ impl<'f> Combine for Sub<'f> {
|
||||
if_ok!(self.get_ref().var_sub_var(a_id, b_id));
|
||||
Ok(a)
|
||||
}
|
||||
// The vec/str check here and below is so that we don't unify
|
||||
// T with [T], this is necessary so we reflect subtyping of references
|
||||
// (&T does not unify with &[T]) where that in turn is to reflect
|
||||
// the historical non-typedness of [T].
|
||||
(&ty::ty_infer(TyVar(_)), &ty::ty_str) |
|
||||
(&ty::ty_infer(TyVar(_)), &ty::ty_vec(_, None)) => {
|
||||
Err(ty::terr_sorts(expected_found(self, a, b)))
|
||||
}
|
||||
(&ty::ty_infer(TyVar(a_id)), _) => {
|
||||
if_ok!(self.get_ref().var_sub_t(a_id, b));
|
||||
Ok(a)
|
||||
}
|
||||
|
||||
(&ty::ty_str, &ty::ty_infer(TyVar(_))) |
|
||||
(&ty::ty_vec(_, None), &ty::ty_infer(TyVar(_))) => {
|
||||
Err(ty::terr_sorts(expected_found(self, a, b)))
|
||||
}
|
||||
(_, &ty::ty_infer(TyVar(b_id))) => {
|
||||
if_ok!(self.get_ref().t_sub_var(a, b_id));
|
||||
Ok(a)
|
||||
|
@ -741,11 +741,7 @@ impl<'a> ConstraintContext<'a> {
|
||||
self.add_constraints_from_mt(mt, variance);
|
||||
}
|
||||
|
||||
ty::ty_vec(ref mt, _) => {
|
||||
self.add_constraints_from_mt(mt, variance);
|
||||
}
|
||||
|
||||
ty::ty_uniq(typ) | ty::ty_box(typ) => {
|
||||
ty::ty_uniq(typ) | ty::ty_box(typ) | ty::ty_vec(typ, _) | ty::ty_open(typ) => {
|
||||
self.add_constraints_from_ty(typ, variance);
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,7 @@ use middle::ty::{ReSkolemized, ReVar};
|
||||
use middle::ty::{mt, t, ParamTy};
|
||||
use middle::ty::{ty_bool, ty_char, ty_bot, ty_box, ty_struct, ty_enum};
|
||||
use middle::ty::{ty_err, ty_str, ty_vec, ty_float, ty_bare_fn, ty_closure};
|
||||
use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup};
|
||||
use middle::ty::{ty_nil, ty_param, ty_ptr, ty_rptr, ty_tup, ty_open};
|
||||
use middle::ty::{ty_unboxed_closure};
|
||||
use middle::ty::{ty_uniq, ty_trait, ty_int, ty_uint, ty_infer};
|
||||
use middle::ty;
|
||||
@ -370,6 +370,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
buf.push_str(mt_to_string(cx, tm).as_slice());
|
||||
buf
|
||||
}
|
||||
ty_open(typ) => format!("opened<{}>", ty_to_string(cx, typ)),
|
||||
ty_tup(ref elems) => {
|
||||
let strs: Vec<String> = elems.iter().map(|elem| ty_to_string(cx, *elem)).collect();
|
||||
format!("({})", strs.connect(","))
|
||||
@ -407,7 +408,7 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
let trait_def = ty::lookup_trait_def(cx, did);
|
||||
let ty = parameterized(cx, base.as_slice(),
|
||||
substs, &trait_def.generics);
|
||||
let bound_sep = if bounds.is_empty() { "" } else { ":" };
|
||||
let bound_sep = if bounds.is_empty() { "" } else { "+" };
|
||||
let bound_str = bounds.repr(cx);
|
||||
format!("{}{}{}",
|
||||
ty,
|
||||
@ -416,12 +417,12 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String {
|
||||
}
|
||||
ty_str => "str".to_string(),
|
||||
ty_unboxed_closure(..) => "closure".to_string(),
|
||||
ty_vec(ref mt, sz) => {
|
||||
ty_vec(t, sz) => {
|
||||
match sz {
|
||||
Some(n) => {
|
||||
format!("[{}, .. {}]", mt_to_string(cx, mt), n)
|
||||
format!("[{}, .. {}]", ty_to_string(cx, t), n)
|
||||
}
|
||||
None => format!("[{}]", ty_to_string(cx, mt.ty)),
|
||||
None => format!("[{}]", ty_to_string(cx, t)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,14 +20,8 @@ pub static fn_field_box: uint = 1u;
|
||||
|
||||
// The two fields of a trait object/trait instance: vtable and box.
|
||||
// The vtable contains the type descriptor as first element.
|
||||
pub static trt_field_vtable: uint = 0u;
|
||||
pub static trt_field_box: uint = 1u;
|
||||
|
||||
pub static vec_elt_fill: uint = 0u;
|
||||
|
||||
pub static vec_elt_alloc: uint = 1u;
|
||||
|
||||
pub static vec_elt_elems: uint = 2u;
|
||||
pub static trt_field_box: uint = 0u;
|
||||
pub static trt_field_vtable: uint = 1u;
|
||||
|
||||
pub static slice_elt_base: uint = 0u;
|
||||
pub static slice_elt_len: uint = 1u;
|
||||
|
@ -225,7 +225,6 @@ mod svh_visitor {
|
||||
SawExprBreak(Option<token::InternedString>),
|
||||
SawExprAgain(Option<token::InternedString>),
|
||||
|
||||
SawExprVstore,
|
||||
SawExprBox,
|
||||
SawExprVec,
|
||||
SawExprCall,
|
||||
@ -257,7 +256,6 @@ mod svh_visitor {
|
||||
|
||||
fn saw_expr<'a>(node: &'a Expr_) -> SawExprComponent<'a> {
|
||||
match *node {
|
||||
ExprVstore(..) => SawExprVstore,
|
||||
ExprBox(..) => SawExprBox,
|
||||
ExprVec(..) => SawExprVec,
|
||||
ExprCall(..) => SawExprCall,
|
||||
|
@ -1250,8 +1250,8 @@ impl Clean<Type> for ty::t {
|
||||
});
|
||||
lang_struct(box_did, t, "Box", Unique)
|
||||
}
|
||||
ty::ty_vec(mt, None) => Vector(box mt.ty.clean()),
|
||||
ty::ty_vec(mt, Some(i)) => FixedVector(box mt.ty.clean(),
|
||||
ty::ty_vec(ty, None) => Vector(box ty.clean()),
|
||||
ty::ty_vec(ty, Some(i)) => FixedVector(box ty.clean(),
|
||||
format!("{}", i)),
|
||||
ty::ty_ptr(mt) => RawPointer(mt.mutbl.clean(), box mt.ty.clean()),
|
||||
ty::ty_rptr(r, mt) => BorrowedRef {
|
||||
@ -1315,6 +1315,7 @@ impl Clean<Type> for ty::t {
|
||||
ty::ty_unboxed_closure(..) => Primitive(Unit), // FIXME(pcwalton)
|
||||
|
||||
ty::ty_infer(..) => fail!("ty_infer"),
|
||||
ty::ty_open(..) => fail!("ty_open"),
|
||||
ty::ty_err => fail!("ty_err"),
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,8 @@ pub fn run(mut krate: clean::Crate, external_html: &ExternalHtml, dst: Path) ->
|
||||
|
||||
// Crawl the crate attributes looking for attributes which control how we're
|
||||
// going to emit HTML
|
||||
match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(&[])) {
|
||||
let default: &[_] = &[];
|
||||
match krate.module.as_ref().map(|m| m.doc_list().unwrap_or(default)) {
|
||||
Some(attrs) => {
|
||||
for attr in attrs.iter() {
|
||||
match *attr {
|
||||
|
@ -72,13 +72,15 @@ impl Clone for HomeHandle {
|
||||
}
|
||||
|
||||
pub fn local_id() -> uint {
|
||||
use std::raw::TraitObject;
|
||||
|
||||
let mut io = match LocalIo::borrow() {
|
||||
Some(io) => io, None => return 0,
|
||||
};
|
||||
let io = io.get();
|
||||
unsafe {
|
||||
let (_vtable, ptr): (uint, uint) = mem::transmute(io);
|
||||
return ptr;
|
||||
let obj: TraitObject = mem::transmute(io);
|
||||
return mem::transmute(obj.data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -462,13 +462,14 @@ pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
|
||||
// This function is full of lies!
|
||||
#[cfg(test)]
|
||||
fn local_loop() -> &'static mut uvio::UvIoFactory {
|
||||
use std::raw::TraitObject;
|
||||
unsafe {
|
||||
mem::transmute({
|
||||
let mut task = Local::borrow(None::<Task>);
|
||||
let mut io = task.local_io().unwrap();
|
||||
let (_vtable, uvio): (uint, &'static mut uvio::UvIoFactory) =
|
||||
let obj: TraitObject =
|
||||
mem::transmute(io.get());
|
||||
uvio
|
||||
obj.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -183,16 +183,17 @@ mod tests {
|
||||
#[test]
|
||||
pub fn test_from_hex_all_bytes() {
|
||||
for i in range(0u, 256) {
|
||||
let ii: &[u8] = &[i as u8];
|
||||
assert_eq!(format!("{:02x}", i as uint).as_slice()
|
||||
.from_hex()
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[i as u8]);
|
||||
ii);
|
||||
assert_eq!(format!("{:02X}", i as uint).as_slice()
|
||||
.from_hex()
|
||||
.unwrap()
|
||||
.as_slice(),
|
||||
&[i as u8]);
|
||||
ii);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,11 +609,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_ascii_vec() {
|
||||
let test = &[40u8, 32u8, 59u8];
|
||||
assert_eq!(test.to_ascii(), v2ascii!([40, 32, 59]));
|
||||
assert_eq!("( ;".to_ascii(), v2ascii!([40, 32, 59]));
|
||||
let b: &[_] = v2ascii!([40, 32, 59]);
|
||||
assert_eq!(test.to_ascii(), b);
|
||||
assert_eq!("( ;".to_ascii(), b);
|
||||
let v = vec![40u8, 32u8, 59u8];
|
||||
assert_eq!(v.as_slice().to_ascii(), v2ascii!([40, 32, 59]));
|
||||
assert_eq!("( ;".to_string().as_slice().to_ascii(), v2ascii!([40, 32, 59]));
|
||||
assert_eq!(v.as_slice().to_ascii(), b);
|
||||
assert_eq!("( ;".to_string().as_slice().to_ascii(), b);
|
||||
|
||||
assert_eq!("abCDef&?#".to_ascii().to_lower().into_string(), "abcdef&?#".to_string());
|
||||
assert_eq!("abCDef&?#".to_ascii().to_upper().into_string(), "ABCDEF&?#".to_string());
|
||||
@ -688,13 +689,12 @@ mod tests {
|
||||
assert_eq!((test1).to_ascii_opt(), None);
|
||||
|
||||
let v = [40u8, 32u8, 59u8];
|
||||
let v2 = v2ascii!(&[40, 32, 59]);
|
||||
let v2: &[_] = v2ascii!(&[40, 32, 59]);
|
||||
assert_eq!(v.to_ascii_opt(), Some(v2));
|
||||
let v = [127u8, 128u8, 255u8];
|
||||
assert_eq!(v.to_ascii_opt(), None);
|
||||
|
||||
let v = "( ;";
|
||||
let v2 = v2ascii!(&[40, 32, 59]);
|
||||
assert_eq!(v.to_ascii_opt(), Some(v2));
|
||||
assert_eq!("zoä华".to_ascii_opt(), None);
|
||||
|
||||
|
@ -415,21 +415,25 @@ mod test {
|
||||
let mut buf = [0, 0, 0];
|
||||
let nread = reader.read(buf);
|
||||
assert_eq!(Ok(2), nread);
|
||||
assert_eq!(buf.as_slice(), &[0, 1, 0]);
|
||||
let b: &[_] = &[0, 1, 0];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
|
||||
let mut buf = [0];
|
||||
let nread = reader.read(buf);
|
||||
assert_eq!(Ok(1), nread);
|
||||
assert_eq!(buf.as_slice(), &[2]);
|
||||
let b: &[_] = &[2];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
|
||||
let mut buf = [0, 0, 0];
|
||||
let nread = reader.read(buf);
|
||||
assert_eq!(Ok(1), nread);
|
||||
assert_eq!(buf.as_slice(), &[3, 0, 0]);
|
||||
let b: &[_] = &[3, 0, 0];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
|
||||
let nread = reader.read(buf);
|
||||
assert_eq!(Ok(1), nread);
|
||||
assert_eq!(buf.as_slice(), &[4, 0, 0]);
|
||||
let b: &[_] = &[4, 0, 0];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
|
||||
assert!(reader.read(buf).is_err());
|
||||
}
|
||||
@ -440,35 +444,41 @@ mod test {
|
||||
let mut writer = BufferedWriter::with_capacity(2, inner);
|
||||
|
||||
writer.write([0, 1]).unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(), &[]);
|
||||
let b: &[_] = &[];
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
|
||||
writer.write([2]).unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(), &[0, 1]);
|
||||
let b: &[_] = &[0, 1];
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
|
||||
writer.write([3]).unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(), &[0, 1]);
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
|
||||
writer.flush().unwrap();
|
||||
assert_eq!(&[0, 1, 2, 3], writer.get_ref().get_ref());
|
||||
let a: &[_] = &[0, 1, 2, 3];
|
||||
assert_eq!(a, writer.get_ref().get_ref());
|
||||
|
||||
writer.write([4]).unwrap();
|
||||
writer.write([5]).unwrap();
|
||||
assert_eq!(&[0, 1, 2, 3], writer.get_ref().get_ref());
|
||||
assert_eq!(a, writer.get_ref().get_ref());
|
||||
|
||||
writer.write([6]).unwrap();
|
||||
assert_eq!(&[0, 1, 2, 3, 4, 5],
|
||||
let a: &[_] = &[0, 1, 2, 3, 4, 5];
|
||||
assert_eq!(a,
|
||||
writer.get_ref().get_ref());
|
||||
|
||||
writer.write([7, 8]).unwrap();
|
||||
assert_eq!(&[0, 1, 2, 3, 4, 5, 6],
|
||||
let a: &[_] = &[0, 1, 2, 3, 4, 5, 6];
|
||||
assert_eq!(a,
|
||||
writer.get_ref().get_ref());
|
||||
|
||||
writer.write([9, 10, 11]).unwrap();
|
||||
assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
||||
let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
|
||||
assert_eq!(a,
|
||||
writer.get_ref().get_ref());
|
||||
|
||||
writer.flush().unwrap();
|
||||
assert_eq!(&[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11],
|
||||
assert_eq!(a,
|
||||
writer.get_ref().get_ref());
|
||||
}
|
||||
|
||||
@ -476,9 +486,11 @@ mod test {
|
||||
fn test_buffered_writer_inner_flushes() {
|
||||
let mut w = BufferedWriter::with_capacity(3, MemWriter::new());
|
||||
w.write([0, 1]).unwrap();
|
||||
assert_eq!(&[], w.get_ref().get_ref());
|
||||
let a: &[_] = &[];
|
||||
assert_eq!(a, w.get_ref().get_ref());
|
||||
let w = w.unwrap();
|
||||
assert_eq!(&[0, 1], w.get_ref());
|
||||
let a: &[_] = &[0, 1];
|
||||
assert_eq!(a, w.get_ref());
|
||||
}
|
||||
|
||||
// This is just here to make sure that we don't infinite loop in the
|
||||
@ -519,20 +531,22 @@ mod test {
|
||||
fn test_line_buffer() {
|
||||
let mut writer = LineBufferedWriter::new(MemWriter::new());
|
||||
writer.write([0]).unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(), &[]);
|
||||
let b: &[_] = &[];
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
writer.write([1]).unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(), &[]);
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
writer.flush().unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(), &[0, 1]);
|
||||
let b: &[_] = &[0, 1];
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
writer.write([0, b'\n', 1, b'\n', 2]).unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(),
|
||||
&[0, 1, 0, b'\n', 1, b'\n']);
|
||||
let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n'];
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
writer.flush().unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(),
|
||||
&[0, 1, 0, b'\n', 1, b'\n', 2]);
|
||||
let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2];
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
writer.write([3, b'\n']).unwrap();
|
||||
assert_eq!(writer.get_ref().get_ref(),
|
||||
&[0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
|
||||
let b: &[_] = &[0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n'];
|
||||
assert_eq!(writer.get_ref().get_ref(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -154,26 +154,29 @@ mod test {
|
||||
assert_eq!(Ok(0), reader.read([]));
|
||||
|
||||
assert_eq!(Ok(3), reader.read(buf));
|
||||
assert_eq!(&[1,2,3], buf.as_slice());
|
||||
let a: &[u8] = &[1,2,3];
|
||||
assert_eq!(a, buf.as_slice());
|
||||
|
||||
assert_eq!(Ok(3), reader.read(buf));
|
||||
assert_eq!(&[4,5,6], buf.as_slice());
|
||||
let a: &[u8] = &[4,5,6];
|
||||
assert_eq!(a, buf.as_slice());
|
||||
|
||||
assert_eq!(Ok(2), reader.read(buf));
|
||||
assert_eq!(&[7,8,6], buf.as_slice());
|
||||
let a: &[u8] = &[7,8,6];
|
||||
assert_eq!(a, buf.as_slice());
|
||||
|
||||
match reader.read(buf.as_mut_slice()) {
|
||||
Ok(..) => fail!(),
|
||||
Err(e) => assert_eq!(e.kind, io::EndOfFile),
|
||||
}
|
||||
assert_eq!(&[7,8,6], buf.as_slice());
|
||||
assert_eq!(a, buf.as_slice());
|
||||
|
||||
// Ensure it continues to fail in the same way.
|
||||
match reader.read(buf.as_mut_slice()) {
|
||||
Ok(..) => fail!(),
|
||||
Err(e) => assert_eq!(e.kind, io::EndOfFile),
|
||||
}
|
||||
assert_eq!(&[7,8,6], buf.as_slice());
|
||||
assert_eq!(a, buf.as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -346,7 +346,8 @@ mod test {
|
||||
writer.write([0]).unwrap();
|
||||
writer.write([1, 2, 3]).unwrap();
|
||||
writer.write([4, 5, 6, 7]).unwrap();
|
||||
assert_eq!(writer.get_ref(), &[0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
|
||||
assert_eq!(writer.get_ref(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -363,7 +364,8 @@ mod test {
|
||||
writer.write([]).unwrap();
|
||||
assert_eq!(writer.tell(), Ok(8));
|
||||
}
|
||||
assert_eq!(buf.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7]);
|
||||
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -391,7 +393,8 @@ mod test {
|
||||
assert_eq!(writer.tell(), Ok(8));
|
||||
|
||||
}
|
||||
assert_eq!(buf.as_slice(), &[1, 3, 2, 0, 0, 0, 0, 4]);
|
||||
let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -415,13 +418,16 @@ mod test {
|
||||
let mut buf = [0];
|
||||
assert_eq!(reader.read(buf), Ok(1));
|
||||
assert_eq!(reader.tell(), Ok(1));
|
||||
assert_eq!(buf.as_slice(), &[0]);
|
||||
let b: &[_] = &[0];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
let mut buf = [0, ..4];
|
||||
assert_eq!(reader.read(buf), Ok(4));
|
||||
assert_eq!(reader.tell(), Ok(5));
|
||||
assert_eq!(buf.as_slice(), &[1, 2, 3, 4]);
|
||||
let b: &[_] = &[1, 2, 3, 4];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
assert_eq!(reader.read(buf), Ok(3));
|
||||
assert_eq!(buf.slice(0, 3), &[5, 6, 7]);
|
||||
let b: &[_] = &[5, 6, 7];
|
||||
assert_eq!(buf.slice(0, 3), b);
|
||||
assert!(reader.read(buf).is_err());
|
||||
let mut reader = MemReader::new(vec!(0, 1, 2, 3, 4, 5, 6, 7));
|
||||
assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
|
||||
@ -439,13 +445,16 @@ mod test {
|
||||
let mut buf = [0];
|
||||
assert_eq!(reader.read(buf), Ok(1));
|
||||
assert_eq!(reader.tell(), Ok(1));
|
||||
assert_eq!(buf.as_slice(), &[0]);
|
||||
let b: &[_] = &[0];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
let mut buf = [0, ..4];
|
||||
assert_eq!(reader.read(buf), Ok(4));
|
||||
assert_eq!(reader.tell(), Ok(5));
|
||||
assert_eq!(buf.as_slice(), &[1, 2, 3, 4]);
|
||||
let b: &[_] = &[1, 2, 3, 4];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
assert_eq!(reader.read(buf), Ok(3));
|
||||
assert_eq!(buf.slice(0, 3), &[5, 6, 7]);
|
||||
let b: &[_] = &[5, 6, 7];
|
||||
assert_eq!(buf.slice(0, 3), b);
|
||||
assert!(reader.read(buf).is_err());
|
||||
let mut reader = BufReader::new(in_buf.as_slice());
|
||||
assert_eq!(reader.read_until(3).unwrap(), vec!(0, 1, 2, 3));
|
||||
@ -537,13 +546,16 @@ mod test {
|
||||
let mut r = MemReader::new(vec![1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
let mut buf = [0, ..3];
|
||||
assert!(r.read_at_least(buf.len(), buf).is_ok());
|
||||
assert_eq!(buf.as_slice(), &[1, 2, 3]);
|
||||
let b: &[_] = &[1, 2, 3];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
assert!(r.read_at_least(0, buf.mut_slice_to(0)).is_ok());
|
||||
assert_eq!(buf.as_slice(), &[1, 2, 3]);
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
assert!(r.read_at_least(buf.len(), buf).is_ok());
|
||||
assert_eq!(buf.as_slice(), &[4, 5, 6]);
|
||||
let b: &[_] = &[4, 5, 6];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
assert!(r.read_at_least(buf.len(), buf).is_err());
|
||||
assert_eq!(buf.as_slice(), &[7, 8, 6]);
|
||||
let b: &[_] = &[7, 8, 6];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
}
|
||||
|
||||
fn do_bench_mem_writer(b: &mut Bencher, times: uint, len: uint) {
|
||||
|
@ -111,7 +111,8 @@ mod test {
|
||||
Ok(MemReader::new(vec!(0, 1, 2, 3)));
|
||||
let mut buf = [0, 0];
|
||||
reader.read(buf).unwrap();
|
||||
assert_eq!(buf.as_slice(), &[0, 1]);
|
||||
let b: &[_] = &[0, 1];
|
||||
assert_eq!(buf.as_slice(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -295,7 +295,8 @@ pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
|
||||
for p in input.iter() {
|
||||
let mut it = p.as_slice().splitn(1, |b| *b == b'=');
|
||||
let key = Vec::from_slice(it.next().unwrap());
|
||||
let val = Vec::from_slice(it.next().unwrap_or(&[]));
|
||||
let default: &[u8] = &[];
|
||||
let val = Vec::from_slice(it.next().unwrap_or(default));
|
||||
pairs.push((key, val));
|
||||
}
|
||||
pairs
|
||||
|
@ -846,7 +846,10 @@ impl<'a, P: GenericPath> Display<'a, P> {
|
||||
pub fn as_maybe_owned(&self) -> MaybeOwned<'a> {
|
||||
String::from_utf8_lossy(if self.filename {
|
||||
match self.path.filename() {
|
||||
None => &[],
|
||||
None => {
|
||||
let result: &[u8] = &[];
|
||||
result
|
||||
}
|
||||
Some(v) => v
|
||||
}
|
||||
} else {
|
||||
|
@ -464,6 +464,7 @@ static dot_dot_static: &'static [u8] = b"..";
|
||||
mod tests {
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
use mem;
|
||||
use str;
|
||||
use str::StrSlice;
|
||||
|
||||
@ -621,8 +622,10 @@ mod tests {
|
||||
macro_rules! t(
|
||||
(s: $path:expr, $op:ident, $exp:expr) => (
|
||||
{
|
||||
let path = Path::new($path);
|
||||
assert!(path.$op() == ($exp).as_bytes());
|
||||
unsafe {
|
||||
let path = Path::new($path);
|
||||
assert!(path.$op() == mem::transmute(($exp).as_bytes()));
|
||||
}
|
||||
}
|
||||
);
|
||||
(s: $path:expr, $op:ident, $exp:expr, opt) => (
|
||||
@ -634,9 +637,11 @@ mod tests {
|
||||
);
|
||||
(v: $path:expr, $op:ident, $exp:expr) => (
|
||||
{
|
||||
let arg = $path;
|
||||
let path = Path::new(arg);
|
||||
assert!(path.$op() == $exp);
|
||||
unsafe {
|
||||
let arg = $path;
|
||||
let path = Path::new(arg);
|
||||
assert!(path.$op() == mem::transmute($exp));
|
||||
}
|
||||
}
|
||||
);
|
||||
)
|
||||
@ -684,8 +689,9 @@ mod tests {
|
||||
t!(v: b"hi/there.txt", extension, Some(b"txt"));
|
||||
t!(v: b"hi/there\x80.txt", extension, Some(b"txt"));
|
||||
t!(v: b"hi/there.t\x80xt", extension, Some(b"t\x80xt"));
|
||||
t!(v: b"hi/there", extension, None);
|
||||
t!(v: b"hi/there\x80", extension, None);
|
||||
let no: Option<&'static [u8]> = None;
|
||||
t!(v: b"hi/there", extension, no);
|
||||
t!(v: b"hi/there\x80", extension, no);
|
||||
t!(s: "hi/there.txt", extension, Some("txt"), opt);
|
||||
t!(s: "hi/there", extension, None, opt);
|
||||
t!(s: "there.txt", extension, Some("txt"), opt);
|
||||
@ -974,57 +980,62 @@ mod tests {
|
||||
macro_rules! t(
|
||||
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
let filename = $filename;
|
||||
assert!(path.filename_str() == filename,
|
||||
"{}.filename_str(): Expected `{:?}`, found {:?}",
|
||||
path.as_str().unwrap(), filename, path.filename_str());
|
||||
let dirname = $dirname;
|
||||
assert!(path.dirname_str() == dirname,
|
||||
"`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), dirname, path.dirname_str());
|
||||
let filestem = $filestem;
|
||||
assert!(path.filestem_str() == filestem,
|
||||
"`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), filestem, path.filestem_str());
|
||||
let ext = $ext;
|
||||
assert!(path.extension_str() == ext,
|
||||
"`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), ext, path.extension_str());
|
||||
unsafe {
|
||||
let path = $path;
|
||||
let filename = $filename;
|
||||
assert!(path.filename_str() == filename,
|
||||
"{}.filename_str(): Expected `{:?}`, found {:?}",
|
||||
path.as_str().unwrap(), filename, path.filename_str());
|
||||
let dirname = $dirname;
|
||||
assert!(path.dirname_str() == dirname,
|
||||
"`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), dirname, path.dirname_str());
|
||||
let filestem = $filestem;
|
||||
assert!(path.filestem_str() == filestem,
|
||||
"`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), filestem, path.filestem_str());
|
||||
let ext = $ext;
|
||||
assert!(path.extension_str() == mem::transmute(ext),
|
||||
"`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), ext, path.extension_str());
|
||||
}
|
||||
}
|
||||
);
|
||||
(v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
assert!(path.filename() == $filename);
|
||||
assert!(path.dirname() == $dirname);
|
||||
assert!(path.filestem() == $filestem);
|
||||
assert!(path.extension() == $ext);
|
||||
unsafe {
|
||||
let path = $path;
|
||||
assert!(path.filename() == mem::transmute($filename));
|
||||
assert!(path.dirname() == mem::transmute($dirname));
|
||||
assert!(path.filestem() == mem::transmute($filestem));
|
||||
assert!(path.extension() == mem::transmute($ext));
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None);
|
||||
t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None);
|
||||
let no: Option<&'static str> = None;
|
||||
t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), no);
|
||||
t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), no);
|
||||
t!(v: Path::new(b"hi/there.\xFF"), Some(b"there.\xFF"), b"hi",
|
||||
Some(b"there"), Some(b"\xFF"));
|
||||
t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None);
|
||||
t!(s: Path::new("."), None, Some("."), None, None);
|
||||
t!(s: Path::new("/"), None, Some("/"), None, None);
|
||||
t!(s: Path::new(".."), None, Some(".."), None, None);
|
||||
t!(s: Path::new("../.."), None, Some("../.."), None, None);
|
||||
t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), no);
|
||||
t!(s: Path::new("."), None, Some("."), None, no);
|
||||
t!(s: Path::new("/"), None, Some("/"), None, no);
|
||||
t!(s: Path::new(".."), None, Some(".."), None, no);
|
||||
t!(s: Path::new("../.."), None, Some("../.."), None, no);
|
||||
t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"),
|
||||
Some("there"), Some("txt"));
|
||||
t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None);
|
||||
t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), no);
|
||||
t!(s: Path::new("hi/there."), Some("there."), Some("hi"),
|
||||
Some("there"), Some(""));
|
||||
t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None);
|
||||
t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), no);
|
||||
t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"),
|
||||
Some("."), Some("there"));
|
||||
t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, None);
|
||||
t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, no);
|
||||
t!(s: Path::new(b"a/b/\xFF.txt"), None, Some("a/b"), None, Some("txt"));
|
||||
t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), None);
|
||||
t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), None);
|
||||
t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), no);
|
||||
t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), no);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1141,6 +1141,7 @@ fn prefix_len(p: Option<PathPrefix>) -> uint {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use mem;
|
||||
use prelude::*;
|
||||
use super::*;
|
||||
use super::parse_prefix;
|
||||
@ -1383,9 +1384,11 @@ mod tests {
|
||||
macro_rules! t(
|
||||
(s: $path:expr, $op:ident, $exp:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
let path = Path::new(path);
|
||||
assert!(path.$op() == Some($exp));
|
||||
unsafe {
|
||||
let path = $path;
|
||||
let path = Path::new(path);
|
||||
assert!(path.$op() == Some(mem::transmute($exp)));
|
||||
}
|
||||
}
|
||||
);
|
||||
(s: $path:expr, $op:ident, $exp:expr, opt) => (
|
||||
@ -1398,9 +1401,11 @@ mod tests {
|
||||
);
|
||||
(v: $path:expr, $op:ident, $exp:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
let path = Path::new(path);
|
||||
assert!(path.$op() == $exp);
|
||||
unsafe {
|
||||
let path = $path;
|
||||
let path = Path::new(path);
|
||||
assert!(path.$op() == mem::transmute($exp));
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
@ -1485,7 +1490,8 @@ mod tests {
|
||||
// filestem is based on filename, so we don't need the full set of prefix tests
|
||||
|
||||
t!(v: b"hi\\there.txt", extension, Some(b"txt"));
|
||||
t!(v: b"hi\\there", extension, None);
|
||||
let no: Option<&'static [u8]> = None;
|
||||
t!(v: b"hi\\there", extension, no);
|
||||
t!(s: "hi\\there.txt", extension_str, Some("txt"), opt);
|
||||
t!(s: "hi\\there", extension_str, None, opt);
|
||||
t!(s: "there.txt", extension_str, Some("txt"), opt);
|
||||
@ -1892,48 +1898,53 @@ mod tests {
|
||||
macro_rules! t(
|
||||
(s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
let filename = $filename;
|
||||
assert!(path.filename_str() == filename,
|
||||
"`{}`.filename_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), filename, path.filename_str());
|
||||
let dirname = $dirname;
|
||||
assert!(path.dirname_str() == dirname,
|
||||
"`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), dirname, path.dirname_str());
|
||||
let filestem = $filestem;
|
||||
assert!(path.filestem_str() == filestem,
|
||||
"`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), filestem, path.filestem_str());
|
||||
let ext = $ext;
|
||||
assert!(path.extension_str() == ext,
|
||||
"`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), ext, path.extension_str());
|
||||
unsafe {
|
||||
let path = $path;
|
||||
let filename = $filename;
|
||||
assert!(path.filename_str() == filename,
|
||||
"`{}`.filename_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), filename, path.filename_str());
|
||||
let dirname = $dirname;
|
||||
assert!(path.dirname_str() == dirname,
|
||||
"`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), dirname, path.dirname_str());
|
||||
let filestem = $filestem;
|
||||
assert!(path.filestem_str() == filestem,
|
||||
"`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), filestem, path.filestem_str());
|
||||
let ext = $ext;
|
||||
assert!(path.extension_str() == mem::transmute(ext),
|
||||
"`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
|
||||
path.as_str().unwrap(), ext, path.extension_str());
|
||||
}
|
||||
}
|
||||
);
|
||||
(v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
|
||||
{
|
||||
let path = $path;
|
||||
assert!(path.filename() == $filename);
|
||||
assert!(path.dirname() == $dirname);
|
||||
assert!(path.filestem() == $filestem);
|
||||
assert!(path.extension() == $ext);
|
||||
unsafe {
|
||||
let path = $path;
|
||||
assert!(path.filename() == mem::transmute($filename));
|
||||
assert!(path.dirname() == mem::transmute($dirname));
|
||||
assert!(path.filestem() == mem::transmute($filestem));
|
||||
assert!(path.extension() == mem::transmute($ext));
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None);
|
||||
t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None);
|
||||
t!(s: Path::new("."), None, Some("."), None, None);
|
||||
t!(s: Path::new("\\"), None, Some("\\"), None, None);
|
||||
t!(s: Path::new(".."), None, Some(".."), None, None);
|
||||
t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None);
|
||||
let no: Option<&'static str> = None;
|
||||
t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), no);
|
||||
t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), no);
|
||||
t!(s: Path::new("."), None, Some("."), None, no);
|
||||
t!(s: Path::new("\\"), None, Some("\\"), None, no);
|
||||
t!(s: Path::new(".."), None, Some(".."), None, no);
|
||||
t!(s: Path::new("..\\.."), None, Some("..\\.."), None, no);
|
||||
t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"),
|
||||
Some("there"), Some("txt"));
|
||||
t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None);
|
||||
t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), no);
|
||||
t!(s: Path::new("hi\\there."), Some("there."), Some("hi"),
|
||||
Some("there"), Some(""));
|
||||
t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None);
|
||||
t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), no);
|
||||
t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"),
|
||||
Some("."), Some("there"));
|
||||
|
||||
|
@ -531,7 +531,8 @@ mod test {
|
||||
r.shuffle(empty);
|
||||
let mut one = [1i];
|
||||
r.shuffle(one);
|
||||
assert_eq!(one.as_slice(), &[1]);
|
||||
let b: &[_] = &[1];
|
||||
assert_eq!(one.as_slice(), b);
|
||||
|
||||
let mut two = [1i, 2];
|
||||
r.shuffle(two);
|
||||
@ -539,7 +540,8 @@ mod test {
|
||||
|
||||
let mut x = [1i, 1, 1];
|
||||
r.shuffle(x);
|
||||
assert_eq!(x.as_slice(), &[1, 1, 1]);
|
||||
let b: &[_] = &[1, 1, 1];
|
||||
assert_eq!(x.as_slice(), b);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -548,7 +550,8 @@ mod test {
|
||||
r.gen::<int>();
|
||||
let mut v = [1i, 1, 1];
|
||||
r.shuffle(v);
|
||||
assert_eq!(v.as_slice(), &[1, 1, 1]);
|
||||
let b: &[_] = &[1, 1, 1];
|
||||
assert_eq!(v.as_slice(), b);
|
||||
assert_eq!(r.gen_range(0u, 1u), 0u);
|
||||
}
|
||||
|
||||
|
@ -394,16 +394,6 @@ pub enum Mutability {
|
||||
MutImmutable,
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
pub enum ExprVstore {
|
||||
/// ~[1, 2, 3, 4]
|
||||
ExprVstoreUniq,
|
||||
/// &[1, 2, 3, 4]
|
||||
ExprVstoreSlice,
|
||||
/// &mut [1, 2, 3, 4]
|
||||
ExprVstoreMutSlice,
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
pub enum BinOp {
|
||||
BiAdd,
|
||||
@ -522,7 +512,6 @@ pub struct Expr {
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
pub enum Expr_ {
|
||||
ExprVstore(Gc<Expr>, ExprVstore),
|
||||
/// First expr is the place; second expr is the value.
|
||||
ExprBox(Gc<Expr>, Gc<Expr>),
|
||||
ExprVec(Vec<Gc<Expr>>),
|
||||
|
@ -143,12 +143,10 @@ pub trait AstBuilder {
|
||||
fn expr_u8(&self, sp: Span, u: u8) -> Gc<ast::Expr>;
|
||||
fn expr_bool(&self, sp: Span, value: bool) -> Gc<ast::Expr>;
|
||||
|
||||
fn expr_vstore(&self, sp: Span, expr: Gc<ast::Expr>, vst: ast::ExprVstore) -> Gc<ast::Expr>;
|
||||
fn expr_vec(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr>;
|
||||
fn expr_vec_ng(&self, sp: Span) -> Gc<ast::Expr>;
|
||||
fn expr_vec_slice(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr>;
|
||||
fn expr_str(&self, sp: Span, s: InternedString) -> Gc<ast::Expr>;
|
||||
fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc<ast::Expr>;
|
||||
|
||||
fn expr_some(&self, sp: Span, expr: Gc<ast::Expr>) -> Gc<ast::Expr>;
|
||||
fn expr_none(&self, sp: Span) -> Gc<ast::Expr>;
|
||||
@ -654,9 +652,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
self.expr_lit(sp, ast::LitBool(value))
|
||||
}
|
||||
|
||||
fn expr_vstore(&self, sp: Span, expr: Gc<ast::Expr>, vst: ast::ExprVstore) -> Gc<ast::Expr> {
|
||||
self.expr(sp, ast::ExprVstore(expr, vst))
|
||||
}
|
||||
fn expr_vec(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr> {
|
||||
self.expr(sp, ast::ExprVec(exprs))
|
||||
}
|
||||
@ -669,15 +664,11 @@ impl<'a> AstBuilder for ExtCtxt<'a> {
|
||||
Vec::new())
|
||||
}
|
||||
fn expr_vec_slice(&self, sp: Span, exprs: Vec<Gc<ast::Expr>> ) -> Gc<ast::Expr> {
|
||||
self.expr_vstore(sp, self.expr_vec(sp, exprs), ast::ExprVstoreSlice)
|
||||
self.expr_addr_of(sp, self.expr_vec(sp, exprs))
|
||||
}
|
||||
fn expr_str(&self, sp: Span, s: InternedString) -> Gc<ast::Expr> {
|
||||
self.expr_lit(sp, ast::LitStr(s, ast::CookedStr))
|
||||
}
|
||||
fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc<ast::Expr> {
|
||||
self.expr_vstore(sp, self.expr_str(sp, s), ast::ExprVstoreUniq)
|
||||
}
|
||||
|
||||
|
||||
fn expr_cast(&self, sp: Span, expr: Gc<ast::Expr>, ty: P<ast::Ty>) -> Gc<ast::Expr> {
|
||||
self.expr(sp, ast::ExprCast(expr, ty))
|
||||
|
@ -1088,9 +1088,6 @@ pub fn noop_fold_pat<T: Folder>(p: Gc<Pat>, folder: &mut T) -> Gc<Pat> {
|
||||
pub fn noop_fold_expr<T: Folder>(e: Gc<Expr>, folder: &mut T) -> Gc<Expr> {
|
||||
let id = folder.new_id(e.id);
|
||||
let node = match e.node {
|
||||
ExprVstore(e, v) => {
|
||||
ExprVstore(folder.fold_expr(e), v)
|
||||
}
|
||||
ExprBox(p, e) => {
|
||||
ExprBox(folder.fold_expr(p), folder.fold_expr(e))
|
||||
}
|
||||
|
@ -1137,7 +1137,8 @@ mod test {
|
||||
let item = parse_item_from_source_str(name.clone(), source, Vec::new(), &sess).unwrap();
|
||||
let docs = item.attrs.iter().filter(|a| a.name().get() == "doc")
|
||||
.map(|a| a.value_str().unwrap().get().to_string()).collect::<Vec<_>>();
|
||||
assert_eq!(docs.as_slice(), &["/// doc comment".to_string(), "/// line 2".to_string()]);
|
||||
let b: &[_] = &["/// doc comment".to_string(), "/// line 2".to_string()];
|
||||
assert_eq!(docs.as_slice(), b);
|
||||
|
||||
let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string();
|
||||
let item = parse_item_from_source_str(name, source, Vec::new(), &sess).unwrap();
|
||||
|
@ -27,9 +27,8 @@ use ast::{ExprField, ExprFnBlock, ExprIf, ExprIndex};
|
||||
use ast::{ExprLit, ExprLoop, ExprMac};
|
||||
use ast::{ExprMethodCall, ExprParen, ExprPath, ExprProc};
|
||||
use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary, ExprUnboxedFn};
|
||||
use ast::{ExprVec, ExprVstore, ExprVstoreSlice};
|
||||
use ast::{ExprVstoreMutSlice, ExprWhile, ExprForLoop, Field, FnDecl};
|
||||
use ast::{ExprVstoreUniq, Once, Many};
|
||||
use ast::{ExprVec, ExprWhile, ExprForLoop, Field, FnDecl};
|
||||
use ast::{Once, Many};
|
||||
use ast::{FnUnboxedClosureKind, FnMutUnboxedClosureKind};
|
||||
use ast::{FnOnceUnboxedClosureKind};
|
||||
use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod};
|
||||
@ -62,7 +61,7 @@ use ast::{UnsafeFn, ViewItem, ViewItem_, ViewItemExternCrate, ViewItemUse};
|
||||
use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
|
||||
use ast::{Visibility, WhereClause, WherePredicate};
|
||||
use ast;
|
||||
use ast_util::{as_prec, ident_to_path, lit_is_str, operator_prec};
|
||||
use ast_util::{as_prec, ident_to_path, operator_prec};
|
||||
use ast_util;
|
||||
use attr;
|
||||
use codemap::{Span, BytePos, Spanned, spanned, mk_sp};
|
||||
@ -1428,13 +1427,16 @@ impl<'a> Parser<'a> {
|
||||
} else if self.token == token::TILDE {
|
||||
// OWNED POINTER
|
||||
self.bump();
|
||||
let last_span = self.last_span;
|
||||
let span = self.last_span;
|
||||
match self.token {
|
||||
token::LBRACKET =>
|
||||
self.obsolete(last_span, ObsoleteOwnedVector),
|
||||
_ => self.obsolete(last_span, ObsoleteOwnedType),
|
||||
};
|
||||
TyUniq(self.parse_ty(true))
|
||||
token::IDENT(ref ident, _)
|
||||
if "str" == token::get_ident(*ident).get() => {
|
||||
// This is OK (for now).
|
||||
}
|
||||
token::LBRACKET => {} // Also OK.
|
||||
_ => self.obsolete(span, ObsoleteOwnedType)
|
||||
}
|
||||
TyUniq(self.parse_ty(false))
|
||||
} else if self.token == token::BINOP(token::STAR) {
|
||||
// STAR POINTER (bare pointer?)
|
||||
self.bump();
|
||||
@ -2549,16 +2551,7 @@ impl<'a> Parser<'a> {
|
||||
let m = self.parse_mutability();
|
||||
let e = self.parse_prefix_expr();
|
||||
hi = e.span.hi;
|
||||
// HACK: turn &[...] into a &-vec
|
||||
ex = match e.node {
|
||||
ExprVec(..) if m == MutImmutable => {
|
||||
ExprVstore(e, ExprVstoreSlice)
|
||||
}
|
||||
ExprVec(..) if m == MutMutable => {
|
||||
ExprVstore(e, ExprVstoreMutSlice)
|
||||
}
|
||||
_ => ExprAddrOf(m, e)
|
||||
};
|
||||
ex = ExprAddrOf(m, e);
|
||||
}
|
||||
token::AT => {
|
||||
self.bump();
|
||||
@ -2570,61 +2563,43 @@ impl<'a> Parser<'a> {
|
||||
}
|
||||
token::TILDE => {
|
||||
self.bump();
|
||||
let span = self.last_span;
|
||||
match self.token {
|
||||
token::LIT_STR(_) => {
|
||||
// This is OK (for now).
|
||||
}
|
||||
token::LBRACKET => {} // Also OK.
|
||||
_ => self.obsolete(span, ObsoleteOwnedExpr)
|
||||
}
|
||||
|
||||
let e = self.parse_prefix_expr();
|
||||
hi = e.span.hi;
|
||||
// HACK: turn ~[...] into a ~-vec
|
||||
let last_span = self.last_span;
|
||||
ex = match e.node {
|
||||
ExprVec(..) | ExprRepeat(..) => {
|
||||
self.obsolete(last_span, ObsoleteOwnedVector);
|
||||
ExprVstore(e, ExprVstoreUniq)
|
||||
}
|
||||
ExprLit(lit) if lit_is_str(lit) => {
|
||||
self.obsolete(last_span, ObsoleteOwnedExpr);
|
||||
ExprVstore(e, ExprVstoreUniq)
|
||||
}
|
||||
_ => {
|
||||
self.obsolete(last_span, ObsoleteOwnedExpr);
|
||||
self.mk_unary(UnUniq, e)
|
||||
}
|
||||
};
|
||||
ex = self.mk_unary(UnUniq, e);
|
||||
}
|
||||
token::IDENT(_, _) => {
|
||||
if self.is_keyword(keywords::Box) {
|
||||
self.bump();
|
||||
if !self.is_keyword(keywords::Box) {
|
||||
return self.parse_dot_or_call_expr();
|
||||
}
|
||||
|
||||
// Check for a place: `box(PLACE) EXPR`.
|
||||
if self.eat(&token::LPAREN) {
|
||||
// Support `box() EXPR` as the default.
|
||||
if !self.eat(&token::RPAREN) {
|
||||
let place = self.parse_expr();
|
||||
self.expect(&token::RPAREN);
|
||||
let subexpression = self.parse_prefix_expr();
|
||||
hi = subexpression.span.hi;
|
||||
ex = ExprBox(place, subexpression);
|
||||
return self.mk_expr(lo, hi, ex);
|
||||
}
|
||||
self.bump();
|
||||
|
||||
// Check for a place: `box(PLACE) EXPR`.
|
||||
if self.eat(&token::LPAREN) {
|
||||
// Support `box() EXPR` as the default.
|
||||
if !self.eat(&token::RPAREN) {
|
||||
let place = self.parse_expr();
|
||||
self.expect(&token::RPAREN);
|
||||
let subexpression = self.parse_prefix_expr();
|
||||
hi = subexpression.span.hi;
|
||||
ex = ExprBox(place, subexpression);
|
||||
return self.mk_expr(lo, hi, ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, we use the unique pointer default.
|
||||
let subexpression = self.parse_prefix_expr();
|
||||
hi = subexpression.span.hi;
|
||||
// HACK: turn `box [...]` into a boxed-vec
|
||||
ex = match subexpression.node {
|
||||
ExprVec(..) | ExprRepeat(..) => {
|
||||
let last_span = self.last_span;
|
||||
self.obsolete(last_span, ObsoleteOwnedVector);
|
||||
ExprVstore(subexpression, ExprVstoreUniq)
|
||||
}
|
||||
ExprLit(lit) if lit_is_str(lit) => {
|
||||
ExprVstore(subexpression, ExprVstoreUniq)
|
||||
}
|
||||
_ => self.mk_unary(UnUniq, subexpression)
|
||||
};
|
||||
} else {
|
||||
return self.parse_dot_or_call_expr()
|
||||
}
|
||||
// Otherwise, we use the unique pointer default.
|
||||
let subexpression = self.parse_prefix_expr();
|
||||
hi = subexpression.span.hi;
|
||||
ex = self.mk_unary(UnUniq, subexpression);
|
||||
}
|
||||
_ => return self.parse_dot_or_call_expr()
|
||||
}
|
||||
|
@ -159,6 +159,7 @@ impl<'a> State<'a> {
|
||||
}
|
||||
|
||||
pub fn to_string(f: |&mut State| -> IoResult<()>) -> String {
|
||||
use std::raw::TraitObject;
|
||||
let mut s = rust_printer(box MemWriter::new());
|
||||
f(&mut s).unwrap();
|
||||
eof(&mut s.s).unwrap();
|
||||
@ -166,7 +167,8 @@ pub fn to_string(f: |&mut State| -> IoResult<()>) -> String {
|
||||
// FIXME(pcwalton): A nasty function to extract the string from an `io::Writer`
|
||||
// that we "know" to be a `MemWriter` that works around the lack of checked
|
||||
// downcasts.
|
||||
let (_, wr): (uint, Box<MemWriter>) = mem::transmute_copy(&s.s.out);
|
||||
let obj: TraitObject = mem::transmute_copy(&s.s.out);
|
||||
let wr: Box<MemWriter> = mem::transmute(obj.data);
|
||||
let result =
|
||||
String::from_utf8(Vec::from_slice(wr.get_ref().as_slice())).unwrap();
|
||||
mem::forget(wr);
|
||||
@ -1321,16 +1323,6 @@ impl<'a> State<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn print_expr_vstore(&mut self, t: ast::ExprVstore) -> IoResult<()> {
|
||||
match t {
|
||||
ast::ExprVstoreUniq => word(&mut self.s, "box "),
|
||||
ast::ExprVstoreSlice => word(&mut self.s, "&"),
|
||||
ast::ExprVstoreMutSlice => {
|
||||
try!(word(&mut self.s, "&"));
|
||||
word(&mut self.s, "mut")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn print_call_post(&mut self, args: &[Gc<ast::Expr>]) -> IoResult<()> {
|
||||
try!(self.popen());
|
||||
@ -1355,10 +1347,6 @@ impl<'a> State<'a> {
|
||||
try!(self.ibox(indent_unit));
|
||||
try!(self.ann.pre(self, NodeExpr(expr)));
|
||||
match expr.node {
|
||||
ast::ExprVstore(ref e, v) => {
|
||||
try!(self.print_expr_vstore(v));
|
||||
try!(self.print_expr(&**e));
|
||||
},
|
||||
ast::ExprBox(ref p, ref e) => {
|
||||
try!(word(&mut self.s, "box"));
|
||||
try!(word(&mut self.s, "("));
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user