diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index ab686cb01d66c..38216fa5b59b1 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -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) } diff --git a/src/libcollections/bitv.rs b/src/libcollections/bitv.rs index 10ebcbcab36b8..d13767077c7ac 100644 --- a/src/libcollections/bitv.rs +++ b/src/libcollections/bitv.rs @@ -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) } diff --git a/src/libcollections/dlist.rs b/src/libcollections/dlist.rs index 2899bdc0ddb6f..418bb147d204a 100644 --- a/src/libcollections/dlist.rs +++ b/src/libcollections/dlist.rs @@ -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::>().as_slice()); + let a: &[_] = &[&1,&2,&3]; + assert_eq!(a, n.iter().collect::>().as_slice()); }); } diff --git a/src/libcollections/hash/mod.rs b/src/libcollections/hash/mod.rs index b867bb7be0422..ef26452a52902 100644 --- a/src/libcollections/hash/mod.rs +++ b/src/libcollections/hash/mod.rs @@ -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); diff --git a/src/libcollections/hash/sip.rs b/src/libcollections/hash/sip.rs index 09a0edd9e3a9a..f3798e5f9e009 100644 --- a/src/libcollections/hash/sip.rs +++ b/src/libcollections/hash/sip.rs @@ -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)); diff --git a/src/libcollections/ringbuf.rs b/src/libcollections/ringbuf.rs index c9b60e67edde3..2f0fbfadb17f3 100644 --- a/src/libcollections/ringbuf.rs +++ b/src/libcollections/ringbuf.rs @@ -243,7 +243,8 @@ impl RingBuf { /// buf.push(5i); /// buf.push(3); /// buf.push(4); - /// assert_eq!(buf.iter().collect::>().as_slice(), &[&5, &3, &4]); + /// let b: &[_] = &[&5, &3, &4]; + /// assert_eq!(buf.iter().collect::>().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 RingBuf { /// for num in buf.mut_iter() { /// *num = *num - 2; /// } - /// assert_eq!(buf.mut_iter().collect::>().as_slice(), &[&mut 3, &mut 1, &mut 2]); + /// let b: &[_] = &[&mut 3, &mut 1, &mut 2]; + /// assert_eq!(buf.mut_iter().collect::>().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::>().as_slice(), &[&0,&1,&2,&3,&4]); + { + let b: &[_] = &[&0,&1,&2,&3,&4]; + assert_eq!(d.iter().collect::>().as_slice(), b); + } for i in range(6i, 9) { d.push_front(i); } - assert_eq!(d.iter().collect::>().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::>().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::>().as_slice(), &[&4,&3,&2,&1,&0]); + { + let b: &[_] = &[&4,&3,&2,&1,&0]; + assert_eq!(d.iter().rev().collect::>().as_slice(), b); + } for i in range(6i, 9) { d.push_front(i); } - assert_eq!(d.iter().rev().collect::>().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::>().as_slice(), b); } #[test] diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index c137cc25b252a..71b9673d27929 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -638,11 +638,13 @@ pub trait MutableOrdSlice { /// # 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 { /// # 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::>().as_slice(), - &[&[1], &[3], &[5]]); + splits); + let splits: &[&[int]] = &[&[], &[2,3,4,5]]; assert_eq!(xs.split(|x| *x == 1).collect::>().as_slice(), - &[&[], &[2,3,4,5]]); + splits); + let splits: &[&[int]] = &[&[1,2,3,4], &[]]; assert_eq!(xs.split(|x| *x == 5).collect::>().as_slice(), - &[&[1,2,3,4], &[]]); + splits); + let splits: &[&[int]] = &[&[1,2,3,4,5]]; assert_eq!(xs.split(|x| *x == 10).collect::>().as_slice(), - &[&[1,2,3,4,5]]); + splits); + let splits: &[&[int]] = &[&[], &[], &[], &[], &[], &[]]; assert_eq!(xs.split(|_| true).collect::>().as_slice(), - &[&[], &[], &[], &[], &[], &[]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.split(|x| *x == 5).collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.split(|x| *x == 5).collect::>().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::>().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::>().as_slice(), - &[&[1], &[3,4,5]]); + splits); + let splits: &[&[int]] = &[&[], &[], &[], &[4,5]]; assert_eq!(xs.splitn(3, |_| true).collect::>().as_slice(), - &[&[], &[], &[], &[4,5]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.splitn(1, |x| *x == 5).collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.splitn(1, |x| *x == 5).collect::>().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::>().as_slice(), - &[&[5], &[3], &[1]]); + splits); + let splits: &[&[int]] = &[&[2,3,4,5], &[]]; assert_eq!(xs.split(|x| *x == 1).rev().collect::>().as_slice(), - &[&[2,3,4,5], &[]]); + splits); + let splits: &[&[int]] = &[&[], &[1,2,3,4]]; assert_eq!(xs.split(|x| *x == 5).rev().collect::>().as_slice(), - &[&[], &[1,2,3,4]]); + splits); + let splits: &[&[int]] = &[&[1,2,3,4,5]]; assert_eq!(xs.split(|x| *x == 10).rev().collect::>().as_slice(), - &[&[1,2,3,4,5]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.split(|x| *x == 5).rev().collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.split(|x| *x == 5).rev().collect::>().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::>().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::>().as_slice(), - &[&[5], &[1,2,3]]); + splits); + let splits: &[&[int]] = &[&[], &[], &[], &[1,2]]; assert_eq!(xs.rsplitn(3, |_| true).collect::>().as_slice(), - &[&[], &[], &[], &[1,2]]); + splits); let xs: &[int] = &[]; - assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::>().as_slice(), &[&[]]); + let splits: &[&[int]] = &[&[]]; + assert_eq!(xs.rsplitn(1, |x| *x == 5).collect::>().as_slice(), splits); } #[test] fn test_windowsator() { let v = &[1i,2,3,4]; - assert_eq!(v.windows(2).collect::>().as_slice(), &[&[1,2], &[2,3], &[3,4]]); - assert_eq!(v.windows(3).collect::>().as_slice(), &[&[1i,2,3], &[2,3,4]]); + let wins: &[&[int]] = &[&[1,2], &[2,3], &[3,4]]; + assert_eq!(v.windows(2).collect::>().as_slice(), wins); + let wins: &[&[int]] = &[&[1i,2,3], &[2,3,4]]; + assert_eq!(v.windows(3).collect::>().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::>().as_slice(), &[&[1i,2], &[3,4], &[5]]); - assert_eq!(v.chunks(3).collect::>().as_slice(), &[&[1i,2,3], &[4,5]]); - assert_eq!(v.chunks(6).collect::>().as_slice(), &[&[1i,2,3,4,5]]); + let chunks: &[&[int]] = &[&[1i,2], &[3,4], &[5]]; + assert_eq!(v.chunks(2).collect::>().as_slice(), chunks); + let chunks: &[&[int]] = &[&[1i,2,3], &[4,5]]; + assert_eq!(v.chunks(3).collect::>().as_slice(), chunks); + let chunks: &[&[int]] = &[&[1i,2,3,4,5]]; + assert_eq!(v.chunks(6).collect::>().as_slice(), chunks); - assert_eq!(v.chunks(2).rev().collect::>().as_slice(), &[&[5i], &[3,4], &[1,2]]); + let chunks: &[&[int]] = &[&[5i], &[3,4], &[1,2]]; + assert_eq!(v.chunks(2).rev().collect::>().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] diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs index 9120b3889e77f..3f9a179872e14 100644 --- a/src/libcollections/str.rs +++ b/src/libcollections/str.rs @@ -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::>(); - 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::>(); - 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::>(); - 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] diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 89fdc4d42fb88..05d91a7504150 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -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] diff --git a/src/libcollections/treemap.rs b/src/libcollections/treemap.rs index 4ab33b05aaa63..8e5ffbd168660 100644 --- a/src/libcollections/treemap.rs +++ b/src/libcollections/treemap.rs @@ -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) { diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index bfd10c835e206..b90c6daf9ebae 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -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] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 84827c63572cf..4ecc1b8f45fc0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -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; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 4de81db1013c4..f0c39766ebb30 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -174,7 +174,7 @@ pub unsafe fn overwrite(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(dst: &mut T, src: T) { ptr::write(dst, src) } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index bf8a92a4f950a..7773e03416e9e 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -221,8 +221,14 @@ impl Option { #[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 Slice for Option { fn as_slice<'a>(&'a self) -> &'a [T] { match *self { Some(ref x) => slice::ref_slice(x), - None => &[] + None => { + let result: &[_] = &[]; + result + } } } } diff --git a/src/libcore/raw.rs b/src/libcore/raw.rs index da9fab0fc6f50..5daa693c77400 100644 --- a/src/libcore/raw.rs +++ b/src/libcore/raw.rs @@ -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. diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index 826f25101fb70..475c2e94ec778 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1623,7 +1623,6 @@ pub mod bytes { - // // Boilerplate traits // @@ -1649,6 +1648,27 @@ impl<'a,T:PartialEq, V: Slice> Equiv 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> Equiv 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 { diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 66564b1bf07dc..5cbeda94d0f86 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -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(&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(&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(&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(&self, search: C) -> Option; @@ -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(&self, search: C) -> Option; diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs index d25ffb5b84c8a..99ac7cfed027f 100644 --- a/src/libcoretest/iter.rs +++ b/src/libcoretest/iter.rs @@ -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)); diff --git a/src/libdebug/reflect.rs b/src/libdebug/reflect.rs index 0cbae6ee2d3a3..b89ea4d373ddc 100644 --- a/src/libdebug/reflect.rs +++ b/src/libdebug/reflect.rs @@ -193,6 +193,8 @@ impl TyVisitor for MovePtrAdaptor { 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 TyVisitor for MovePtrAdaptor { 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 TyVisitor for MovePtrAdaptor { 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); diff --git a/src/libdebug/repr.rs b/src/libdebug/repr.rs index b85097e6623dc..20f96d24a5f5f 100644 --- a/src/libdebug/repr.rs +++ b/src/libdebug/repr.rs @@ -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'{'])); diff --git a/src/libgreen/context.rs b/src/libgreen/context.rs index 64537ea12d983..296615e15ffa0 100644 --- a/src/libgreen/context.rs +++ b/src/libgreen/context.rs @@ -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); } } } diff --git a/src/libnum/bigint.rs b/src/libnum/bigint.rs index 48fc9fb4a38c6..ba45d2b2e73ff 100644 --- a/src/libnum/bigint.rs +++ b/src/libnum/bigint.rs @@ -1449,8 +1449,8 @@ mod biguint_tests { #[test] fn test_cmp() { - let data: Vec = [ &[], &[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 = 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)); diff --git a/src/librand/isaac.rs b/src/librand/isaac.rs index 2fbfa6d6e85a0..0f7cda42a8a0c 100644 --- a/src/librand/isaac.rs +++ b/src/librand/isaac.rs @@ -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(); } diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 9c33b713e4a6b..5f460225d39a9 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -309,7 +309,8 @@ pub trait SeedableRng: 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::()); /// rng.reseed([5, 6, 7, 8]); /// println!("{}", rng.gen::()); @@ -323,7 +324,8 @@ pub trait SeedableRng: 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::()); /// ``` fn from_seed(seed: Seed) -> Self; diff --git a/src/librbml/io.rs b/src/librbml/io.rs index 9ab163c5f4740..443bf4d34ffa1 100644 --- a/src/librbml/io.rs +++ b/src/librbml/io.rs @@ -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] diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index a789049d4de8c..77e73c46c402c 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -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, diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index ceb7dcc54560c..5f26a966f97e7 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -477,13 +477,14 @@ fn mk_test_descs(cx: &TestCtxt) -> Gc { 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, } } diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 80b4764014673..214401b17a1bb 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -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; diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index b26a12d5cfc36..2ef5675caa177 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -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); diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index fc5e267aa9050..84ee49c207b0f 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -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)"); + } } } diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 3359d7ed030c4..6a8ee2675425f 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -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))) + }) + } + } + }); + } + + 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; - 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))) + 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,34 +1526,128 @@ 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| Ok(this.read_auto_deref_ref(xcx))).unwrap(); + + ty::AutoDerefRef(auto_deref_ref) + } + _ => fail!("bad enum variant for ty::AutoAdjustment") + }) + }) + }).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> = + 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::AutoDerefRef(auto_deref_ref.tr(xcx)) + ty::AutoUnsize(uk) } 2 => { - let store: ty::TraitStore = + 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(); - let b: ty::BuiltinBounds = + + 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(2, |this| Decodable::decode(this)).unwrap(); - let substs = this.read_enum_variant_arg(3, |this| Ok(this.read_substs(xcx))) - .unwrap(); + 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::AutoObject(store.tr(xcx), b, def_id.tr(xcx), substs) + ty::UnsizeVtable(b, def_id.tr(xcx), substs) } - _ => fail!("bad enum variant for ty::AutoAdjustment") + _ => fail!("bad enum variant for ty::UnsizeKind") }) }) }).unwrap() diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 9de55ccc46824..230786924d7c4 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -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 { diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index fd3074e130e70..0d77b01d9706d 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -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]) } diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 283d667f3a803..629aba8092c27 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -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") + + } }, _ => { diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs index 8985e633ad464..042a5b8f60aaf 100644 --- a/src/librustc/middle/check_static.rs +++ b/src/librustc/middle/check_static.rs @@ -107,21 +107,19 @@ impl<'a> Visitor 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"); } diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index b6ad584c30305..03a7021b70d0b 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -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(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 { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 84b879227ae6c..67ee5c5e4be55 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -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())); - let cmt_derefd = return_if_err!( - self.mc.cat_expr_autoderefd(expr, autoderefs)); + // 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; + } + _ => {} + } - debug!("walk_autoref: cmt_derefd={}", cmt_derefd.repr(self.tcx())); + let cmt_derefd = return_if_err!( + 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) - } - 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) + AutoRef); } - ty::AutoUnsafe(_) => {} + ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(_) => {} } } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 6669147b0dcac..639f89dc3cced 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -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 diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index dbd7d6a5d6ac4..b96a75cba9480 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -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 => {} diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 2062fa97777d5..38288bf301161 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -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(..) | diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index ef1e0515156c0..2d052feb6720f 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -205,7 +205,7 @@ pub fn opt_deref_kind(t: ty::t) -> Option { 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 { } 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(&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(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(&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))); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 5f5a324857ab9..1a884eaea2132 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -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() { diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index 673872103af60..ccc4dbb21e019 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -403,7 +403,7 @@ impl VecPerParamSpace { 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) } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index d8bdeb0abf6d5..28f396c8bf795 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -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(). diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index bf8caef2e9743..f3f4a88fdee4f 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -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 } @@ -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 { use back::abi::{fn_field_code, slice_elt_base, trt_field_box}; @@ -305,8 +310,7 @@ impl Case { // Box could either be a thin or fat pointer depending on T ty::ty_uniq(t) => match ty::get(t).sty { - // Box<[T]>/Box 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 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::>(); - 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::>(); + 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::>(); + 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 { +fn struct_llfields(cx: &CrateContext, st: &Struct, sizing: bool, dst: bool) -> Vec { 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 { 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)); } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 043636a32c0f6..8968c8cc2599f 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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 , fn_ty: ty::t, - call_info: Option) + call_info: Option, + // 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; diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index d50b30c754521..7566cfbac56c4 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -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); } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index fefd3e326515d..05528d2b3d88e 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -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(..) | diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 07f0dbaf73fc0..b3798c9f84dd4 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -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((a, b, _): (R, S, T)) -> (R, S) { + (a, b) +} + fn const_vec(cx: &CrateContext, e: &ast::Expr, es: &[Gc], 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]| { - 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) } } diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 7a1864448e26b..9ec5234134817 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -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, diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index f69a8af9c08d3..2882eaf10be2f 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -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 { 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 { self.val } - pub fn get_element(&self, - ty: ty::t, - gep: |ValueRef| -> ValueRef) - -> Datum { + // 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 { + 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, } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 88bdb00a7c983..566f71220b05f 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -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_object_type should be the whole thing (e.g, Box) 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, 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,54 +2898,32 @@ 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) - } - ty::ty_str => { - let i8_t = ty::mk_i8(); - heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span) - } - ty::ty_trait(..) => { - MetadataCreationResult::new( - trait_pointer_metadata(cx, t, unique_type_id), - false) - } - _ => { - let pointee_metadata = type_metadata(cx, - pointee_type, - 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_metadata), - false) - } - } + // 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_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_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 => { 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 = type_metadata(cx, mt.ty, usage_site_span); + let pointee_metadata = type_metadata(cx, ty, usage_site_span); match debug_context(cx).type_map .borrow() @@ -3045,7 +2932,8 @@ fn type_metadata(cx: &CrateContext, None => { /* proceed normally */ } }; - MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee), false) + MetadataCreationResult::new(pointer_type_metadata(cx, t, pointee_metadata), + false) } } } @@ -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()); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 748274b1201e5..c49bb7f4e6b9d 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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) @@ -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 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 - } - 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)) + // (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(AutoBorrowObj(..)) => { - unpack_datum!(bcx, auto_borrow_obj(bcx, expr, datum)) + _ => {} + } + } + } + debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); + return DatumBlock::new(bcx, datum); + + fn apply_autoref<'a>(autoref: &ty::AutoRef, + bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum) + -> 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) + -> 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) } - 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(); + } + + // 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), 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())) } } - debug!("after adjustments, datum={}", datum.to_string(bcx.ccx())); - return DatumBlock {bcx: bcx, datum: datum}; - fn auto_slice<'a>( - bcx: &'a Block<'a>, - expr: &ast::Expr, - datum: Datum) - -> 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 unsize_expr<'a>(bcx: &'a Block<'a>, + expr: &ast::Expr, + datum: Datum, + 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) + -> 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, + 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, + len: uint) + -> DatumBlock<'a, Expr> { + let mut bcx = bcx; + let tcx = bcx.tcx(); + + let datum_ty = datum.ty; + // Arrange cleanup + let lval = unpack_datum!(bcx, + datum.to_lvalue_datum(bcx, "unsize_unique_vec", expr.id)); + + 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"); + + 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, + k: &ty::UnsizeKind) + -> 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; + 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 (base, len) = datum.get_vec_base_and_len(bcx); + let info = unsized_info(bcx, k, expr.id, unboxed_ty, |t| ty::mk_uniq(tcx, t)); + Store(bcx, info, get_len(bcx, scratch.val)); - // 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 }); + 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) - -> 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) - -> 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 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` and `Gc` 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`. @@ -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)); - - 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)) - } + if ty::type_is_sized(bcx.tcx(), content_ty) { + 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)) + } 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)) } } diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 570f4d370425d..56841cd4044b6 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -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` 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` 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` 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` 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 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; diff --git a/src/librustc/middle/trans/intrinsic.rs b/src/librustc/middle/trans/intrinsic.rs index 359c8d24f7270..7d8e4679ae302 100644 --- a/src/librustc/middle/trans/intrinsic.rs +++ b/src/librustc/middle/trans/intrinsic.rs @@ -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" diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index a9a308fc16d1b..83bdcc9dead64 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -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>(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, 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); diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 2aff12c2b68c5..11c641f2d75a2 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -66,7 +66,7 @@ impl<'a, 'b> Reflector<'a, 'b> { pub fn c_size_and_align(&mut self, t: ty::t) -> Vec { 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 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() { diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 1241a85e95cfc..94ca520c533f9 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -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); - - let dataptr = get_dataptr(bcx, val); + dataptr, cleanup::HeapExchange, vt.unit_ty); - debug!("alloc_uniq_vec() returned val={}, dataptr={}", - bcx.val_to_string(val), bcx.val_to_string(dataptr)); + debug!(" alloc_uniq_vec() returned dataptr={}, len={}", + bcx.val_to_string(dataptr), count); - 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) diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index e9d92e45f62d9..017d61137e4b0 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -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 { diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 8a445fc48398e..83c792ecf8782 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -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,35 +303,37 @@ 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, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index dc463ffe5df68..2d3096d13eae0 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -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, uint), + UnsizeVtable(ty::BuiltinBounds, + ast::DefId, /* Trait ID */ + subst::Substs /* Trait substitutions */) +} + +#[deriving(Clone)] pub struct AutoDerefRef { pub autoderefs: uint, pub autoref: Option } -#[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>), - /// 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), +} + +// 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) { + 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 { + 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 { + fn type_of_autoref(cx: &ctxt, autoref: &AutoRef) -> Option { + 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 + } + } - /// Convert from Box/&Trait to &Trait - AutoBorrowObj(Region, ast::Mutability), + 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), // Second field is length. + ty_vec(t, Option), // 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), 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) -> t { - mk_t(cx, ty_vec(tm, sz)) +pub fn mk_vec(cx: &ctxt, t: t, sz: Option) -> 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 { 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 { +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 { + match get(ty).sty { + ty_vec(t, _) => Some(t), _ => None } } @@ -2862,15 +3035,10 @@ pub fn index(t: t) -> Option { // 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 { +pub fn array_element_ty(t: t) -> Option { 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}), + 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 + }) + } - ref s => { - cx.sess.span_bug( - span, - format!("borrow-vec associated with bad sty: {:?}", - s).as_slice()); + 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_tup(_) | ty_param(_) | ty_infer(_) | + ty_open(_) | ty_err => {} } }) diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs index 9f475bfd9d5d0..2bfbc67bbeb0f 100644 --- a/src/librustc/middle/ty_fold.rs +++ b/src/librustc/middle/ty_fold.rs @@ -273,6 +273,18 @@ impl TypeFoldable for ty::Generics { } } +impl TypeFoldable for ty::UnsizeKind { + fn fold_with(&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(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(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)), } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index 129a039a267ba..08e78b35e4d58 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -398,10 +398,7 @@ pub fn ast_ty_to_prim_ty(tcx: &ty::ctxt, ast_ty: &ast::Ty) -> Option { 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 { - span_err!(this.tcx().sess, path.span, E0111, - "`Box` 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`"); @@ -537,12 +520,6 @@ enum PointerTy { Uniq } -fn ast_ty_to_mt(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( this: &AC, @@ -601,11 +578,8 @@ fn mk_pointer { - 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,37 +636,33 @@ fn mk_pointer { let result = ast_path_to_trait_ref( this, rscope, trait_def_id, None, path); - let trait_store = match ptr_ty { - Uniq => ty::UniqTraitStore, - RPtr(r) => { - ty::RegionTraitStore(r, a_seq_ty.mutbl) - } - _ => { - tcx.sess.span_err( - path.span, - "~trait or &trait are the only supported \ - forms of casting-to-trait"); - return ty::mk_err(); - } + let static_region = match ptr_ty { + RPtr(r) if r == ty::ReStatic => true, + _ => false }; let bounds = conv_builtin_bounds(this.tcx(), path.span, bounds, - trait_store); + static_region); 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 match ptr_ty { + Uniq => { return ty::mk_uniq(tcx, tr); } - ty::RegionTraitStore(r, m) => { - return ty::mk_rptr(tcx, r, ty::mt{mutbl: m, ty: tr}); + RPtr(r) => { + return ty::mk_rptr(tcx, r, ty::mt{mutbl: a_seq_ty.mutbl, ty: tr}); } - } + _ => { + tcx.sess.span_err( + path.span, + "~trait or &trait are the only supported \ + forms of casting-to-trait"); + return ty::mk_err(); + } + }; } _ => {} } @@ -738,10 +708,7 @@ pub fn ast_ty_to_ty( |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( 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( 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( _ => { }, } 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( 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( fn conv_builtin_bounds(tcx: &ty::ctxt, span: Span, ast_bounds: &Option>, - 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" or //! "Box". - 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(), } } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 18f4607a83cac..77e5fbae6ee1c 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -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; diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index 2359f9d72d2b7..1b10b30b3358e 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -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); + } + } +} diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 245bbe396fd0d..6bb17c90da269 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -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 { - 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 { + // 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 { 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 { + 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 { 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 { + 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 { + fn search_for_autofatptrd_method(&self, + self_ty: ty::t, + autoderefs: uint) + -> Option { /*! * 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) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 02115590c7e10..02464e17bac84 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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); - } - 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()); + 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); + } } - 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]) { 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 diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 3813dd7964244..4f77c89e86c1d 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -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); - - // 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)); + 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. + + 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) => { - link_region(rcx, expr.span, r, - 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); + ty::AutoPtr(r, m, _) => { link_region(rcx, expr.span, r, - ty::BorrowKind::from_mutbl(m), cmt_deref); + ty::BorrowKind::from_mutbl(m), expr_cmt); } - ty::AutoUnsafe(_) => {} + ty::AutoUnsafe(_) | ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) => {} } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index bc53ed58f6fd5..530f8dd4b9ef6 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -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, is_early: bool) -> Option { - 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` - // 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` + // 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,34 +830,72 @@ 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}) - } - }; + _ => {} + } + } + None => {} + } +} - let key = MethodCall::autoobject(ex.id); - resolve_object_cast(ex, object_ty, key); +// 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))) } - AutoAddEnv(..) => {} + &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 } } - 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 } } diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index 892a62249ac3b..7951c8dfc1980 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -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( diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 3dee787b6c906..a6fa9d84600bf 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -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"); diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index 03890250f7701..abf366381139c 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -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(&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, + // [T, ..n] -> &[T] or &mut [T] + fn coerce_unsized_with_borrow(&self, a: ty::t, sty_a: &ty::sty, - b: ty::t) + b: ty::t, + mutbl_b: ast::Mutability) -> CoerceResult { - debug!("coerce_borrowed_string(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)); match *sty_a { - ty::ty_uniq(_) => return Err(ty::terr_mismatch), - _ => return self.subtype(a, b), + 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) } } - pub fn coerce_borrowed_vector(&self, - a: ty::t, - sty_a: &ty::sty, - b: ty::t, - mutbl_b: ast::Mutability) - -> CoerceResult { - debug!("coerce_borrowed_vector(a={}, sty_a={:?}, 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 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); + + 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) + } + } - 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)) - }))) + // 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()))) - } } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index d99d55d4d873d..a57dec9045522 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -529,10 +529,10 @@ pub fn super_tys(this: &C, a: ty::t, b: ty::t) -> cres { 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))) } diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 5b9b37ab8441b..920fa23f31df3 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -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( diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 44c147bfe7f62..a54afb1102fb9 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -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) diff --git a/src/librustc/middle/typeck/variance.rs b/src/librustc/middle/typeck/variance.rs index 97c11b9205970..e6227b9c12829 100644 --- a/src/librustc/middle/typeck/variance.rs +++ b/src/librustc/middle/typeck/variance.rs @@ -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); } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index e0e9f0e6910b2..5dff183108ce8 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -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 = 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)), } } } diff --git a/src/librustc_back/abi.rs b/src/librustc_back/abi.rs index c722beb43ae95..e859a5d21d7e7 100644 --- a/src/librustc_back/abi.rs +++ b/src/librustc_back/abi.rs @@ -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; diff --git a/src/librustc_back/svh.rs b/src/librustc_back/svh.rs index 29668795ed7ba..6af19d948e0e8 100644 --- a/src/librustc_back/svh.rs +++ b/src/librustc_back/svh.rs @@ -225,7 +225,6 @@ mod svh_visitor { SawExprBreak(Option), SawExprAgain(Option), - 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, diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 68e1529fb1770..dc2c0d1d0830d 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1250,8 +1250,8 @@ impl Clean 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 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"), } } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index be62b1cc36f40..6415ee85f5704 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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 { diff --git a/src/librustuv/homing.rs b/src/librustuv/homing.rs index 91614763ce52f..55d9811ccadc0 100644 --- a/src/librustuv/homing.rs +++ b/src/librustuv/homing.rs @@ -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); } } diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index dd80ab3ee78a1..6e948992979d8 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -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::); 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 }) } } diff --git a/src/libserialize/hex.rs b/src/libserialize/hex.rs index f33ecb5f19bc8..1d2fcc8b77b15 100644 --- a/src/libserialize/hex.rs +++ b/src/libserialize/hex.rs @@ -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); } } diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs index b31baa88e0c84..f7b23163dfe48 100644 --- a/src/libstd/ascii.rs +++ b/src/libstd/ascii.rs @@ -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); diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a9b0b33c59ad9..1d638e498d449 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -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] diff --git a/src/libstd/io/comm_adapters.rs b/src/libstd/io/comm_adapters.rs index 53b5fbe3894ed..1c8b047f56f4d 100644 --- a/src/libstd/io/comm_adapters.rs +++ b/src/libstd/io/comm_adapters.rs @@ -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] diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index ea9d08171e6ce..21ab9c1fdd431 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -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) { diff --git a/src/libstd/io/result.rs b/src/libstd/io/result.rs index a69f6c10abf8e..03637079241d6 100644 --- a/src/libstd/io/result.rs +++ b/src/libstd/io/result.rs @@ -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] diff --git a/src/libstd/os.rs b/src/libstd/os.rs index ad666d7003484..f452f8b23e7ba 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -295,7 +295,8 @@ pub fn env_as_bytes() -> Vec<(Vec,Vec)> { 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 diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs index 38d04324fe417..50441cb534de1 100644 --- a/src/libstd/path/mod.rs +++ b/src/libstd/path/mod.rs @@ -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 { diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs index 0a7817c3e0047..06eab31d7bff5 100644 --- a/src/libstd/path/posix.rs +++ b/src/libstd/path/posix.rs @@ -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] diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs index dd87e214c2c96..d9864cfaa6130 100644 --- a/src/libstd/path/windows.rs +++ b/src/libstd/path/windows.rs @@ -1141,6 +1141,7 @@ fn prefix_len(p: Option) -> 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")); diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index b7bf75e39a558..b9b7a02b62f1b 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -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::(); 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); } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 42d9430d7320e..7d5787092a5c5 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -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, ExprVstore), /// First expr is the place; second expr is the value. ExprBox(Gc, Gc), ExprVec(Vec>), diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index f7eddca4b7aed..909f8f1e78ce4 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -143,12 +143,10 @@ pub trait AstBuilder { fn expr_u8(&self, sp: Span, u: u8) -> Gc; fn expr_bool(&self, sp: Span, value: bool) -> Gc; - fn expr_vstore(&self, sp: Span, expr: Gc, vst: ast::ExprVstore) -> Gc; fn expr_vec(&self, sp: Span, exprs: Vec> ) -> Gc; fn expr_vec_ng(&self, sp: Span) -> Gc; fn expr_vec_slice(&self, sp: Span, exprs: Vec> ) -> Gc; fn expr_str(&self, sp: Span, s: InternedString) -> Gc; - fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc; fn expr_some(&self, sp: Span, expr: Gc) -> Gc; fn expr_none(&self, sp: Span) -> Gc; @@ -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, vst: ast::ExprVstore) -> Gc { - self.expr(sp, ast::ExprVstore(expr, vst)) - } fn expr_vec(&self, sp: Span, exprs: Vec> ) -> Gc { 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 { - 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 { self.expr_lit(sp, ast::LitStr(s, ast::CookedStr)) } - fn expr_str_uniq(&self, sp: Span, s: InternedString) -> Gc { - self.expr_vstore(sp, self.expr_str(sp, s), ast::ExprVstoreUniq) - } - fn expr_cast(&self, sp: Span, expr: Gc, ty: P) -> Gc { self.expr(sp, ast::ExprCast(expr, ty)) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index fb96b4b83d7f3..4a0787aeb9efa 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -1088,9 +1088,6 @@ pub fn noop_fold_pat(p: Gc, folder: &mut T) -> Gc { pub fn noop_fold_expr(e: Gc, folder: &mut T) -> Gc { 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)) } diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 17a27a5a39e6d..585b98925cc58 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -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::>(); - 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(); diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 2409912abe461..01de001c043c7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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() } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 6fe44078447e5..d5b6c5652a0cc 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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) = mem::transmute_copy(&s.s.out); + let obj: TraitObject = mem::transmute_copy(&s.s.out); + let wr: Box = 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]) -> 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, "(")); diff --git a/src/libsyntax/util/small_vector.rs b/src/libsyntax/util/small_vector.rs index 43367611ab2b9..517c5e5bf47da 100644 --- a/src/libsyntax/util/small_vector.rs +++ b/src/libsyntax/util/small_vector.rs @@ -64,7 +64,10 @@ impl SmallVector { pub fn as_slice<'a>(&'a self) -> &'a [T] { match self.repr { - Zero => &[], + Zero => { + let result: &[T] = &[]; + result + } One(ref v) => slice::ref_slice(v), Many(ref vs) => vs.as_slice() } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 9e371143311c2..6c6f59f0df639 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -729,9 +729,6 @@ pub fn walk_mac>(_: &mut V, _: &Mac, _: E) { pub fn walk_expr>(visitor: &mut V, expression: &Expr, env: E) { match expression.node { - ExprVstore(ref subexpression, _) => { - visitor.visit_expr(&**subexpression, env.clone()) - } ExprBox(ref place, ref subexpression) => { visitor.visit_expr(&**place, env.clone()); visitor.visit_expr(&**subexpression, env.clone()) diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs index d0b4c6b1e4c74..429a16ec5c89a 100644 --- a/src/libtime/lib.rs +++ b/src/libtime/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -1060,7 +1060,6 @@ pub fn strftime(format: &str, tm: &Tm) -> String { 'w' => (tm.tm_wday as int).to_string(), 'Y' => (tm.tm_year as int + 1900).to_string(), 'y' => format!("{:02d}", (tm.tm_year as int + 1900) % 100), - 'Z' => "".to_string(), // FIXME(pcwalton): Implement this. 'z' => { let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' }; let mut m = num::abs(tm.tm_gmtoff) / 60_i32; diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 262721bd63676..c71cf5557e35f 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -46,9 +46,11 @@ pub trait UnicodeStrSlice<'a> { /// /// ```rust /// let gr1 = "a\u0310e\u0301o\u0308\u0332".graphemes(true).collect::>(); - /// assert_eq!(gr1.as_slice(), &["a\u0310", "e\u0301", "o\u0308\u0332"]); + /// let b: &[_] = &["a\u0310", "e\u0301", "o\u0308\u0332"]; + /// assert_eq!(gr1.as_slice(), b); /// let gr2 = "a\r\nb🇷🇺🇸🇹".graphemes(true).collect::>(); - /// assert_eq!(gr2.as_slice(), &["a", "\r\n", "b", "🇷🇺🇸🇹"]); + /// let b: &[_] = &["a", "\r\n", "b", "🇷🇺🇸🇹"]; + /// assert_eq!(gr2.as_slice(), b); /// ``` fn graphemes(&self, is_extended: bool) -> Graphemes<'a>; @@ -59,7 +61,8 @@ pub trait UnicodeStrSlice<'a> { /// /// ```rust /// let gr_inds = "a̐éö̲\r\n".grapheme_indices(true).collect::>(); - /// 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); /// ``` fn grapheme_indices(&self, is_extended: bool) -> GraphemeIndices<'a>; diff --git a/src/liburl/lib.rs b/src/liburl/lib.rs index 9ced6cb62af00..b5ffdef22e968 100644 --- a/src/liburl/lib.rs +++ b/src/liburl/lib.rs @@ -1095,7 +1095,8 @@ mod tests { t("\0", "%00"); t("\n", "%0A"); - t(&[0u8, 10, 37], "%00%0A%25"); + let a: &[_] = &[0u8, 10, 37]; + t(a, "%00%0A%25"); } #[test] @@ -1130,7 +1131,8 @@ mod tests { t("\0", "%00"); t("\n", "%0A"); - t(&[0u8, 10, 37], "%00%0A%25"); + let a: &[_] = &[0u8, 10, 37]; + t(a, "%00%0A%25"); } #[test] diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs index 5044d82a6eabb..f68ace395aaa5 100644 --- a/src/test/bench/core-map.rs +++ b/src/test/bench/core-map.rs @@ -100,7 +100,8 @@ fn main() { let mut rand = Vec::with_capacity(n_keys); { - let mut rng: IsaacRng = SeedableRng::from_seed(&[1, 1, 1, 1, 1, 1, 1]); + let seed: &[_] = &[1, 1, 1, 1, 1, 1, 1]; + let mut rng: IsaacRng = SeedableRng::from_seed(seed); let mut set = HashSet::new(); while set.len() != n_keys { let next = rng.gen(); diff --git a/src/test/bench/core-set.rs b/src/test/bench/core-set.rs index 1d2d02d7d5926..7f85bc1d700af 100644 --- a/src/test/bench/core-set.rs +++ b/src/test/bench/core-set.rs @@ -164,7 +164,7 @@ fn main() { } }; - let seed = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let seed: &[_] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let max = 200000; { diff --git a/src/test/compile-fail/const-cast-different-types.rs b/src/test/compile-fail/const-cast-different-types.rs index f7d5ddb314557..6b8e126db7790 100644 --- a/src/test/compile-fail/const-cast-different-types.rs +++ b/src/test/compile-fail/const-cast-different-types.rs @@ -9,8 +9,10 @@ // except according to those terms. static a: &'static str = "foo"; -static b: *const u8 = a as *const u8; //~ ERROR non-scalar cast -static c: *const u8 = &a as *const u8; //~ ERROR mismatched types +static b: *const u8 = a as *const u8; +//~^ ERROR mismatched types: expected `*const u8`, found `&'static str` +static c: *const u8 = &a as *const u8; +//~^ ERROR mismatched types: expected `*const u8`, found `&&'static str` fn main() { } diff --git a/src/test/compile-fail/dst-bad-assign-2.rs b/src/test/compile-fail/dst-bad-assign-2.rs new file mode 100644 index 0000000000000..08e5103810436 --- /dev/null +++ b/src/test/compile-fail/dst-bad-assign-2.rs @@ -0,0 +1,46 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Forbid assignment into a dynamically sized type. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +pub fn main() { + // Assignment. + let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box = box Bar1 {f: 36}; + f5.ptr = *z; //~ ERROR dynamically sized type on lhs of assignment +} diff --git a/src/test/compile-fail/dst-bad-assign.rs b/src/test/compile-fail/dst-bad-assign.rs new file mode 100644 index 0000000000000..17149941a7e1a --- /dev/null +++ b/src/test/compile-fail/dst-bad-assign.rs @@ -0,0 +1,46 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Forbid assignment into a dynamically sized type. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +pub fn main() { + // Assignment. + let f5: &mut Fat = &mut Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + let z: Box = box Bar1 {f: 36}; + f5.ptr = Bar1 {f: 36}; //~ ERROR mismatched types: expected `ToBar`, found `Bar1` +} diff --git a/src/test/compile-fail/dst-bad-coerce1.rs b/src/test/compile-fail/dst-bad-coerce1.rs new file mode 100644 index 0000000000000..a609740eaebf5 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce1.rs @@ -0,0 +1,32 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to change the type as well as unsizing. + +struct Fat { + ptr: T +} + +struct Foo; +trait Bar {} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; + let f3: &Fat<[uint]> = f2; + //~^ ERROR mismatched types: expected `&Fat<[uint]>`, found `&Fat<[int, .. 3]>` + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat = &f1; + let f3: &Fat = f2; + //~^ ERROR failed to find an implementation of trait Bar for Foo +} diff --git a/src/test/compile-fail/dst-bad-coerce2.rs b/src/test/compile-fail/dst-bad-coerce2.rs new file mode 100644 index 0000000000000..118e4ce7e0834 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce2.rs @@ -0,0 +1,31 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to change the mutability as well as unsizing. + +struct Fat { + ptr: T +} + +struct Foo; +trait Bar {} +impl Bar for Foo {} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; + let f3: &mut Fat<[int]> = f2; //~ ERROR cannot borrow immutable dereference + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat = &f1; + let f3: &mut Fat = f2; //~ ERROR cannot borrow immutable dereference +} diff --git a/src/test/compile-fail/dst-bad-coerce3.rs b/src/test/compile-fail/dst-bad-coerce3.rs new file mode 100644 index 0000000000000..7cf647a26d7a7 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce3.rs @@ -0,0 +1,35 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to extend the lifetime as well as unsizing. + +struct Fat { + ptr: T +} + +struct Foo; +trait Bar {} +impl Bar for Foo {} + +fn baz<'a>() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = &f1; //~ ERROR `f1` does not live long enough + let f3: &'a Fat<[int]> = f2; + + // With a trait. + let f1 = Fat { ptr: Foo }; + let f2: &Fat = &f1; //~ ERROR `f1` does not live long enough + let f3: &'a Fat = f2; +} + +pub fn main() { + baz(); +} diff --git a/src/test/compile-fail/dst-bad-coerce4.rs b/src/test/compile-fail/dst-bad-coerce4.rs new file mode 100644 index 0000000000000..9a192334997d2 --- /dev/null +++ b/src/test/compile-fail/dst-bad-coerce4.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Attempt to coerce from unsized to sized. + +struct Fat { + ptr: T +} + +pub fn main() { + // With a vec of ints. + let f1: &Fat<[int]> = &Fat { ptr: [1, 2, 3] }; + let f2: &Fat<[int, ..3]> = f1; + //~^ ERROR mismatched types: expected `&Fat<[int, .. 3]>`, found `&Fat<[int]>` +} diff --git a/src/test/compile-fail/dst-bad-deep.rs b/src/test/compile-fail/dst-bad-deep.rs new file mode 100644 index 0000000000000..cf52639228330 --- /dev/null +++ b/src/test/compile-fail/dst-bad-deep.rs @@ -0,0 +1,25 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Try to initialise a DST struct where the lost information is deeply nested. +// This is an error because it requires an unsized rvalue. This is a problem +// because it would require stack allocation of an unsized temporary (*g in the +// test). + +struct Fat { + ptr: T +} + +pub fn main() { + let f: Fat<[int, ..3]> = Fat { ptr: [5i, 6, 7] }; + let g: &Fat<[int]> = &f; + let h: &Fat> = &Fat { ptr: *g }; + //~^ ERROR trying to initialise a dynamically sized struct +} diff --git a/src/test/compile-fail/issue-10291.rs b/src/test/compile-fail/issue-10291.rs index 71b98bb5f5a48..8ae20dfde9123 100644 --- a/src/test/compile-fail/issue-10291.rs +++ b/src/test/compile-fail/issue-10291.rs @@ -8,11 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn test<'x>(x: &'x int) { //~ NOTE the lifetime 'x as defined +fn test<'x>(x: &'x int) { drop::< <'z>|&'z int| -> &'z int>(|z| { - //~^ ERROR mismatched types - //~^^ ERROR cannot infer an appropriate lifetime x + //~^ ERROR cannot infer an appropriate lifetime }); } diff --git a/src/test/compile-fail/issue-13446.rs b/src/test/compile-fail/issue-13446.rs index 0bb6ded00121d..162324b7c59b2 100644 --- a/src/test/compile-fail/issue-13446.rs +++ b/src/test/compile-fail/issue-13446.rs @@ -11,7 +11,9 @@ // Used to cause ICE -static VEC: [u32, ..256] = vec!(); //~ ERROR mismatched types +// error-pattern: mismatched types + +static VEC: [u32, ..256] = vec!(); fn main() {} diff --git a/src/test/compile-fail/issue-3907-2.rs b/src/test/compile-fail/issue-3907-2.rs index 795e48cb7b005..ab9f7a8453078 100644 --- a/src/test/compile-fail/issue-3907-2.rs +++ b/src/test/compile-fail/issue-3907-2.rs @@ -11,10 +11,12 @@ // aux-build:issue_3907.rs extern crate issue_3907; -type Foo = issue_3907::Foo; //~ ERROR: reference to trait +type Foo = issue_3907::Foo; struct S { name: int } +fn bar(_x: Foo) {} //~ ERROR variable `_x` has dynamically sized type `issue_3907::Foo` + fn main() {} diff --git a/src/test/compile-fail/issue-4523.rs b/src/test/compile-fail/issue-4523.rs index 026327a358a46..5063a78e38348 100644 --- a/src/test/compile-fail/issue-4523.rs +++ b/src/test/compile-fail/issue-4523.rs @@ -10,8 +10,8 @@ fn foopy() {} -static f: ||: 'static = foopy; //~ ERROR found extern fn +static f: ||: 'static = foopy; fn main () { - f(); + f(); //~ ERROR closure invocation in a static location } diff --git a/src/test/compile-fail/issue-4972.rs b/src/test/compile-fail/issue-4972.rs index d684d1b376b8f..199bc3f5c29d9 100644 --- a/src/test/compile-fail/issue-4972.rs +++ b/src/test/compile-fail/issue-4972.rs @@ -17,7 +17,7 @@ pub enum TraitWrapper { fn get_tw_map(tw: &TraitWrapper) -> &MyTrait { match *tw { - A(box ref map) => map, //~ ERROR cannot be dereferenced + A(box ref map) => map, //~ ERROR type `Box` cannot be dereferenced } } diff --git a/src/test/compile-fail/issue-5035-2.rs b/src/test/compile-fail/issue-5035-2.rs index 8d9116da81db2..689b8f7c61360 100644 --- a/src/test/compile-fail/issue-5035-2.rs +++ b/src/test/compile-fail/issue-5035-2.rs @@ -9,6 +9,8 @@ // except according to those terms. trait I {} -type K = I; //~ ERROR: reference to trait +type K = I; + +fn foo(_x: K) {} //~ ERROR: variable `_x` has dynamically sized type `I` fn main() {} diff --git a/src/test/compile-fail/issue-5883.rs b/src/test/compile-fail/issue-5883.rs index 831e165ad0ef5..14136d96c2dff 100644 --- a/src/test/compile-fail/issue-5883.rs +++ b/src/test/compile-fail/issue-5883.rs @@ -11,15 +11,14 @@ trait A {} struct Struct { - r: A //~ ERROR reference to trait `A` where a type is expected; try `Box` or `&A` + r: A } fn new_struct(r: A) -> Struct { - //~^ ERROR reference to trait `A` where a type is expected; try `Box` or `&A` - Struct { r: r } + //~^ ERROR variable `r` has dynamically sized type `A` + Struct { r: r } //~ ERROR trying to initialise a dynamically sized struct } trait Curve {} enum E {X(Curve)} -//~^ ERROR reference to trait `Curve` where a type is expected; try `Box` or `&Curve` fn main() {} diff --git a/src/test/compile-fail/issue-7013.rs b/src/test/compile-fail/issue-7013.rs index ea332c1e25233..ef585998aa5a5 100644 --- a/src/test/compile-fail/issue-7013.rs +++ b/src/test/compile-fail/issue-7013.rs @@ -32,7 +32,7 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR cannot pack type `Box`, which does not fulfill `Send` + //~^ ERROR cannot pack type `Box`, which does not fulfill `Send`, as a trait bounded by Send let v = Rc::new(RefCell::new(a)); let w = v.clone(); let b = &*v; diff --git a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs index ef5a45fcf70ae..481fb3dee73a8 100644 --- a/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs +++ b/src/test/compile-fail/lifetime-inference-give-expl-lifetime-param.rs @@ -36,14 +36,14 @@ fn foo4<'a, 'b>(x: &'a Foo) -> (&'b int, &'a int, &'b int) { struct Bar<'x, 'y, 'z> { bar: &'y int, baz: int } fn bar1<'a>(x: &Bar) -> (&'a int, &'a int, &'a int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar1<'b, 'c, 'a>(x: &'a Bar<'b, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types + (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer //~^ ERROR: cannot infer //~^^ ERROR: cannot infer } fn bar2<'a, 'b, 'c>(x: &Bar<'a, 'b, 'c>) -> (&'a int, &'a int, &'a int) { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn bar2<'a, 'c>(x: &'a Bar<'a, 'a, 'c>) -> (&'a int, &'a int, &'a int) - (x.bar, &x.baz, &x.baz) //~ ERROR: mismatched types + (x.bar, &x.baz, &x.baz) //~ ERROR: cannot infer //~^ ERROR: cannot infer //~^^ ERROR: cannot infer } @@ -53,21 +53,19 @@ struct Dog<'y> { dog: &'y int } fn cat2<'x, 'y>(x: Cat<'x, Dog<'y>>) -> &'x int { //~^ NOTE: consider using an explicit lifetime parameter as shown: fn cat2<'x>(x: Cat<'x, Dog<'x>>) -> &'x int - x.t.dog //~ ERROR: mismatched types + x.t.dog //~ ERROR: cannot infer } struct Baz<'x> { bar: &'x int } - impl<'a> Baz<'a> { fn baz2<'b>(&self, x: &int) -> (&'b int, &'b int) { // The lifetime that gets assigned to `x` seems somewhat random. // I have disabled this test for the time being. --pcwalton (self.bar, x) //~ ERROR: cannot infer - //~^ ERROR: mismatched types - //~^^ ERROR: mismatched types + //~^ ERROR: cannot infer } } diff --git a/src/test/compile-fail/lub-if.rs b/src/test/compile-fail/lub-if.rs index 82938d63ce54c..5440219e55eb9 100644 --- a/src/test/compile-fail/lub-if.rs +++ b/src/test/compile-fail/lub-if.rs @@ -31,18 +31,18 @@ pub fn opt_str1<'a>(maybestr: &'a Option) -> &'a str { } pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { - if maybestr.is_none() { //~ ERROR mismatched types + if maybestr.is_none() { "(none)" } else { let s: &'a str = maybestr.get_ref().as_slice(); - s + s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting } } pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { - if maybestr.is_some() { //~ ERROR mismatched types + if maybestr.is_some() { let s: &'a str = maybestr.get_ref().as_slice(); - s + s //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to conflicting } else { "(none)" } diff --git a/src/test/compile-fail/lub-match.rs b/src/test/compile-fail/lub-match.rs index 98bea422fb5b9..febe5f45d96b0 100644 --- a/src/test/compile-fail/lub-match.rs +++ b/src/test/compile-fail/lub-match.rs @@ -33,7 +33,7 @@ pub fn opt_str1<'a>(maybestr: &'a Option) -> &'a str { } pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { - match *maybestr { //~ ERROR mismatched types + match *maybestr { //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to None => "(none)", Some(ref s) => { let s: &'a str = s.as_slice(); @@ -43,7 +43,7 @@ pub fn opt_str2<'a>(maybestr: &'a Option) -> &'static str { } pub fn opt_str3<'a>(maybestr: &'a Option) -> &'static str { - match *maybestr { //~ ERROR mismatched types + match *maybestr { //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to Some(ref s) => { let s: &'a str = s.as_slice(); s diff --git a/src/test/compile-fail/regions-early-bound-error-method.rs b/src/test/compile-fail/regions-early-bound-error-method.rs index 9c8f8f8c30cc5..0cb88b924f85c 100644 --- a/src/test/compile-fail/regions-early-bound-error-method.rs +++ b/src/test/compile-fail/regions-early-bound-error-method.rs @@ -27,7 +27,7 @@ impl<'a> GetRef<'a> for Box<'a> { impl<'a> Box<'a> { fn or<'b,G:GetRef<'b>>(&self, g2: G) -> &'a int { - g2.get() //~ ERROR lifetime mismatch + g2.get() //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to } } diff --git a/src/test/compile-fail/regions-early-bound-error.rs b/src/test/compile-fail/regions-early-bound-error.rs index 9cff4849cbeb2..25016c104adc8 100644 --- a/src/test/compile-fail/regions-early-bound-error.rs +++ b/src/test/compile-fail/regions-early-bound-error.rs @@ -26,7 +26,7 @@ impl<'a,T:Clone> GetRef<'a,T> for Box<'a,T> { } fn get<'a,'b,G:GetRef<'a, int>>(g1: G, b: &'b int) -> &'b int { - g1.get() //~ ERROR lifetime mismatch + g1.get() //~ ERROR cannot infer an appropriate lifetime for automatic coercion due to } fn main() { diff --git a/src/test/compile-fail/regions-glb-free-free.rs b/src/test/compile-fail/regions-glb-free-free.rs index 1d8c4cec65544..0eb47da16b600 100644 --- a/src/test/compile-fail/regions-glb-free-free.rs +++ b/src/test/compile-fail/regions-glb-free-free.rs @@ -22,9 +22,9 @@ mod argparse { impl<'a> Flag<'a> { pub fn set_desc(self, s: &str) -> Flag<'a> { - Flag { //~ ERROR cannot infer + Flag { name: self.name, - desc: s, + desc: s, //~ ERROR cannot infer an appropriate lifetime for automatic coercion due t max_count: self.max_count, value: self.value } diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index c66e5616b849a..7dc57d37e2496 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -21,8 +21,7 @@ fn nested<'x>(x: &'x int) { }); ignore::< <'z>|&'z int| -> &'z int>(|z| { - if false { return x; } //~ ERROR mismatched types - //~^ ERROR cannot infer + if false { return x; } //~ ERROR cannot infer an appropriate lifetime for automatic if false { return ay; } return z; }); diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index 068ecb7118fc2..df46b2aaac013 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -17,7 +17,7 @@ fn with(f: <'a>|x: &'a int| -> R) -> R { } fn return_it<'a>() -> &'a int { - with(|o| o) //~ ERROR mismatched types + with(|o| o) //~^ ERROR lifetime of return value does not outlive the function call //~^^ ERROR cannot infer } diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index f9983bcf80172..507a48fb74170 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -20,7 +20,7 @@ fn with(f: |x: &int| -> R) -> R { } fn return_it<'a>() -> &'a int { - with(|o| o) //~ ERROR mismatched types + with(|o| o) //~^ ERROR lifetime of return value does not outlive the function call //~^^ ERROR cannot infer } diff --git a/src/test/compile-fail/regions-return-stack-allocated-vec.rs b/src/test/compile-fail/regions-return-stack-allocated-vec.rs index b5f4fcadf89fe..3c5423c44d089 100644 --- a/src/test/compile-fail/regions-return-stack-allocated-vec.rs +++ b/src/test/compile-fail/regions-return-stack-allocated-vec.rs @@ -11,7 +11,7 @@ // Test that we cannot return a stack allocated slice fn function(x: int) -> &'static [int] { - &[x] //~ ERROR mismatched types + &[x] //~ ERROR borrowed value does not live long enough } fn main() { diff --git a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs index f0f388a5a078e..78b4ab817bfac 100644 --- a/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs +++ b/src/test/compile-fail/trait-bounds-not-on-bare-trait.rs @@ -14,7 +14,7 @@ trait Foo { // This should emit the less confusing error, not the more confusing one. fn foo(_x: Foo + Send) { - //~^ERROR reference to trait `Foo` where a type is expected; try `Box` or `&Foo` + //~^ERROR variable `_x` has dynamically sized type `Foo+Send` } fn main() { } diff --git a/src/test/compile-fail/tuple-arity-mismatch.rs b/src/test/compile-fail/tuple-arity-mismatch.rs index 27d272c9f319b..1500a3cbe52db 100644 --- a/src/test/compile-fail/tuple-arity-mismatch.rs +++ b/src/test/compile-fail/tuple-arity-mismatch.rs @@ -13,6 +13,6 @@ fn first((value, _): (int, f64)) -> int { value } fn main() { - let y = first ((1,2,3)); + let y = first ((1,2.0,3)); //~^ ERROR expected a tuple with 2 elements, found one with 3 elements } diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index e1ad27ec5c7a2..7f93c8595f2a2 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -48,8 +48,8 @@ as core::fmt::rt::Piece<'static>)] as [core::fmt::rt::Piece<'static>, .. 1]); let __args_vec = - (&([] as &'static [core::fmt::Argument<'static>]) as - &'static [core::fmt::Argument<'static>]); + (&([] as [core::fmt::Argument<'static>, .. 0]) as + &'static [core::fmt::Argument<'static>, .. 0]); let __args = (unsafe { ((::std::fmt::Arguments::new as @@ -58,7 +58,7 @@ [core::fmt::rt::Piece<'static>, .. 1]), (__args_vec as - &'static [core::fmt::Argument<'static>])) + &'static [core::fmt::Argument<'static>, .. 0])) as core::fmt::Arguments<'static>) } as core::fmt::Arguments<'static>); diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot index bc47d9aff8121..77ee0df5512ef 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -6,37 +6,37 @@ digraph block { N4[label="expr 151i"]; N5[label="local mut y"]; N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l"]; + N9[label="expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l"]; N10[label="expr x"]; N11[label="expr 1i"]; N12[label="expr x == 1i"]; N13[label="expr break \'outer"]; N14[label="(dummy_node)"]; N15[label="expr \"unreachable\""]; - N16[label="block { break \'outer ; \"unreachable\" }"]; - N17[label="expr if x == 1i { break \'outer ; \"unreachable\" }"]; + N16[label="block { break \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1i { break \'outer ; \"unreachable\"; }"]; N18[label="expr y"]; N19[label="expr 2i"]; N20[label="expr y >= 2i"]; N21[label="expr break"]; N22[label="(dummy_node)"]; N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\" }"]; - N25[label="expr if y >= 2i { break ; \"unreachable\" }"]; + N24[label="block { break ; \"unreachable\"; }"]; + N25[label="expr if y >= 2i { break ; \"unreachable\"; }"]; N26[label="expr 3i"]; N27[label="expr y"]; N28[label="expr y -= 3i"]; - N29[label="block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l"]; + N29[label="block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N30[label="expr 4i"]; N31[label="expr y"]; N32[label="expr y -= 4i"]; N33[label="expr 5i"]; N34[label="expr x"]; N35[label="expr x -= 5i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; - N37[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N37[label="block {\l let mut x = 15i;\l let mut y = 151i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l }\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -47,7 +47,7 @@ digraph block { N10 -> N11; N11 -> N12; N12 -> N13; - N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; + N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l }\l y -= 4i;\l x -= 5i;\l}\l"]; N14 -> N15; N15 -> N16; N12 -> N17; @@ -56,7 +56,7 @@ digraph block { N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\" }\l if y >= 2i { break ; \"unreachable\" }\l y -= 3i;\l}\l"]; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 2i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 2i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { break \'outer ; \"unreachable\"; }\l if y >= 2i { break ; \"unreachable\"; }\l y -= 3i;\l}\l"]; N22 -> N23; N23 -> N24; N20 -> N25; diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs index e5ca1de3f2d2c..62233dcb7d8a1 100644 --- a/src/test/run-make/graphviz-flowgraph/f15.rs +++ b/src/test/run-make/graphviz-flowgraph/f15.rs @@ -16,11 +16,11 @@ pub fn expr_break_label_15() { 'inner: loop { if x == 1i { break 'outer; - "unreachable" + "unreachable"; } if y >= 2i { break; - "unreachable" + "unreachable"; } y -= 3i; } diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot index 9c60e19f8b073..b5a867e60297f 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -6,38 +6,38 @@ digraph block { N4[label="expr 16i"]; N5[label="local mut y"]; N6[label="(dummy_node)"]; - N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l"]; N8[label="(dummy_node)"]; - N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l"]; + N9[label="expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l"]; N10[label="expr x"]; N11[label="expr 1i"]; N12[label="expr x == 1i"]; N13[label="expr continue \'outer"]; N14[label="(dummy_node)"]; N15[label="expr \"unreachable\""]; - N16[label="block { continue \'outer ; \"unreachable\" }"]; - N17[label="expr if x == 1i { continue \'outer ; \"unreachable\" }"]; + N16[label="block { continue \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1i { continue \'outer ; \"unreachable\"; }"]; N18[label="expr y"]; N19[label="expr 1i"]; N20[label="expr y >= 1i"]; N21[label="expr break"]; N22[label="(dummy_node)"]; N23[label="expr \"unreachable\""]; - N24[label="block { break ; \"unreachable\" }"]; - N25[label="expr if y >= 1i { break ; \"unreachable\" }"]; + N24[label="block { break ; \"unreachable\"; }"]; + N25[label="expr if y >= 1i { break ; \"unreachable\"; }"]; N26[label="expr 1i"]; N27[label="expr y"]; N28[label="expr y -= 1i"]; - N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l"]; + N29[label="block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; N30[label="expr 1i"]; N31[label="expr y"]; N32[label="expr y -= 1i"]; N33[label="expr 1i"]; N34[label="expr x"]; N35[label="expr x -= 1i"]; - N36[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N37[label="expr \"unreachable\""]; - N38[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; + N38[label="block {\l let mut x = 16i;\l let mut y = 16i;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l }\l \"unreachable\";\l}\l"]; N0 -> N2; N2 -> N3; N3 -> N4; @@ -48,7 +48,7 @@ digraph block { N10 -> N11; N11 -> N12; N12 -> N13; - N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; + N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1i { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l }\l y -= 1i;\l x -= 1i;\l}\l"]; N14 -> N15; N15 -> N16; N12 -> N17; @@ -57,7 +57,7 @@ digraph block { N18 -> N19; N19 -> N20; N20 -> N21; - N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\" }\l if y >= 1i { break ; \"unreachable\" }\l y -= 1i;\l}\l"]; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if y >= 1i { break ; \"unreachable\"; },\lexiting scope_4 stmt if y >= 1i { break ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1i { continue \'outer ; \"unreachable\"; }\l if y >= 1i { break ; \"unreachable\"; }\l y -= 1i;\l}\l"]; N22 -> N23; N23 -> N24; N20 -> N25; diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs index 78de99d28fcce..2683d8bd06b97 100644 --- a/src/test/run-make/graphviz-flowgraph/f16.rs +++ b/src/test/run-make/graphviz-flowgraph/f16.rs @@ -16,11 +16,11 @@ pub fn expr_continue_label_16() { 'inner: loop { if x == 1i { continue 'outer; - "unreachable" + "unreachable"; } if y >= 1i { break; - "unreachable" + "unreachable"; } y -= 1i; } diff --git a/src/test/run-pass/byte-literals.rs b/src/test/run-pass/byte-literals.rs index 7fd7e3dbf0045..058dc426766bc 100644 --- a/src/test/run-pass/byte-literals.rs +++ b/src/test/run-pass/byte-literals.rs @@ -37,13 +37,16 @@ pub fn main() { _ => fail!() } - assert_eq!(b"a\n\r\t\\\'\"\0\xF0", - &[97u8, 10u8, 13u8, 9u8, 92u8, 39u8, 34u8, 0u8, 240u8]); + let expected: &[_] = &[97u8, 10u8, 13u8, 9u8, 92u8, 39u8, 34u8, 0u8, 240u8]; + assert_eq!(b"a\n\r\t\\\'\"\0\xF0", expected); + let expected: &[_] = &[97u8, 98u8]; assert_eq!(b"a\ - b", &[97u8, 98u8]); - assert_eq!(BAR, &[97u8, 240u8, 9u8]); + b", expected); + let expected: &[_] = &[97u8, 240u8, 9u8]; + assert_eq!(BAR, expected); - match &[97u8, 10u8] { + let val: &[_] = &[97u8, 10u8]; + match val { b"a\n" => {}, _ => fail!(), } @@ -55,9 +58,12 @@ pub fn main() { _ => 3u }, 2); - assert_eq!(BAZ, &[97u8, 92u8, 110u8]); - assert_eq!(br"a\n", &[97u8, 92u8, 110u8]); + let expected: &[_] = &[97u8, 92u8, 110u8]; + assert_eq!(BAZ, expected); + let expected: &[_] = &[97u8, 92u8, 110u8]; + assert_eq!(br"a\n", expected); assert_eq!(br"a\n", b"a\\n"); - assert_eq!(br###"a"##b"###, &[97u8, 34u8, 35u8, 35u8, 98u8]); + let expected: &[_] = &[97u8, 34u8, 35u8, 35u8, 98u8]; + assert_eq!(br###"a"##b"###, expected); assert_eq!(br###"a"##b"###, b"a\"##b"); } diff --git a/src/test/run-pass/check-static-slice.rs b/src/test/run-pass/check-static-slice.rs new file mode 100644 index 0000000000000..17957dbcc1389 --- /dev/null +++ b/src/test/run-pass/check-static-slice.rs @@ -0,0 +1,40 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Check that the various ways of getting to a reference to a vec (both sized +// and unsized) work properly. + +static aa: [int, ..3] = [1, 2, 3]; +static ab: &'static [int, ..3] = &aa; +static ac: &'static [int] = ab; +static ad: &'static [int] = &aa; +static ae: &'static [int, ..3] = &[1, 2, 3]; +static af: &'static [int] = &[1, 2, 3]; + +static ca: int = aa[0]; +static cb: int = ab[1]; +static cc: int = ac[2]; +static cd: int = ad[0]; +static ce: int = ae[1]; +static cf: int = af[2]; + +fn main () { + let b: &[int] = &[1, 2, 3]; + assert!(ac == b); + assert!(ad == b); + assert!(af == b); + + assert!(ca == 1); + assert!(cb == 2); + assert!(cc == 3); + assert!(cd == 1); + assert!(ce == 2); + assert!(cf == 3); +} diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index 4c81eaae1d802..5be21696bd1ed 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -12,6 +12,9 @@ enum E { V1(int), V0 } static C: &'static [E] = &[V0, V1(0xDEADBEE)]; static C0: E = C[0]; static C1: E = C[1]; +static D: &'static [E, ..2] = &[V0, V1(0xDEADBEE)]; +static D0: E = C[0]; +static D1: E = C[1]; pub fn main() { match C0 { @@ -22,4 +25,13 @@ pub fn main() { V1(n) => assert!(n == 0xDEADBEE), _ => fail!() } + + match D0 { + V0 => (), + _ => fail!() + } + match D1 { + V1(n) => assert!(n == 0xDEADBEE), + _ => fail!() + } } diff --git a/src/test/run-pass/dst-dtor-1.rs b/src/test/run-pass/dst-dtor-1.rs new file mode 100644 index 0000000000000..6e2ae117ce7ae --- /dev/null +++ b/src/test/run-pass/dst-dtor-1.rs @@ -0,0 +1,34 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static mut DROP_RAN: bool = false; + +struct Foo; +impl Drop for Foo { + fn drop(&mut self) { + unsafe { DROP_RAN = true; } + } +} + +trait Trait {} +impl Trait for Foo {} + +struct Fat { + f: T +} + +pub fn main() { + { + let _x: Box> = box Fat { f: Foo }; + } + unsafe { + assert!(DROP_RAN); + } +} diff --git a/src/test/run-pass/dst-dtor-2.rs b/src/test/run-pass/dst-dtor-2.rs new file mode 100644 index 0000000000000..deaf49228bc84 --- /dev/null +++ b/src/test/run-pass/dst-dtor-2.rs @@ -0,0 +1,31 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +static mut DROP_RAN: int = 0; + +struct Foo; +impl Drop for Foo { + fn drop(&mut self) { + unsafe { DROP_RAN += 1; } + } +} + +struct Fat { + f: T +} + +pub fn main() { + { + let _x: Box> = box Fat { f: [Foo, Foo, Foo] }; + } + unsafe { + assert!(DROP_RAN == 3); + } +} diff --git a/src/test/run-pass/dst-struct-reflect.rs b/src/test/run-pass/dst-struct-reflect.rs new file mode 100644 index 0000000000000..2028ebf64c217 --- /dev/null +++ b/src/test/run-pass/dst-struct-reflect.rs @@ -0,0 +1,61 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME(15049) Re-enable this test. +// ignore-test +// Test that structs with unsized fields work with {:?} reflection. + +extern crate debug; + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +// x is a fat pointer +fn reflect(x: &Fat<[int]>, cmp: &str) { + // Don't test this result because reflecting unsized fields is undefined for now. + let _s = format!("{:?}", x); + let s = format!("{:?}", &x.ptr); + assert!(s == cmp.to_string()) + + println!("{:?}", x); + println!("{:?}", &x.ptr); +} + +fn reflect_0(x: &Fat<[int]>) { + let _s = format!("{:?}", x.ptr[0]); + println!("{:?}", x.ptr[0]); +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + reflect(&f1, "&[1, 2, 3]"); + reflect_0(&f1); + let f2 = &f1; + reflect(f2, "&[1, 2, 3]"); + reflect_0(f2); + let f3: &Fat<[int]> = f2; + reflect(f3, "&[1, 2, 3]"); + reflect_0(f3); + let f4: &Fat<[int]> = &f1; + reflect(f4, "&[1, 2, 3]"); + reflect_0(f4); + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + reflect(f5, "&[1, 2, 3]"); + reflect_0(f5); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + reflect(f5, "&[]"); +} + diff --git a/src/test/run-pass/dst-struct-sole.rs b/src/test/run-pass/dst-struct-sole.rs new file mode 100644 index 0000000000000..04fe6d5cefdc3 --- /dev/null +++ b/src/test/run-pass/dst-struct-sole.rs @@ -0,0 +1,84 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// As dst-struct.rs, but the unsized field is the only field in the struct. + +struct Fat { + ptr: T +} + +// x is a fat pointer +fn foo(x: &Fat<[int]>) { + let y = &x.ptr; + assert!(x.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr[1] == 2); +} + +fn foo2(x: &Fat<[T]>) { + let y = &x.ptr; + let bar = Bar; + assert!(x.ptr.len() == 3); + assert!(y[0].to_bar() == bar); + assert!(x.ptr[1].to_bar() == bar); +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +trait ToBar { + fn to_bar(&self) -> Bar; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { ptr: [1, 2, 3] }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<[int]> = f2; + foo(f3); + let f4: &Fat<[int]> = &f1; + foo(f4); + let f5: &Fat<[int]> = &Fat { ptr: [1, 2, 3] }; + foo(f5); + + // With a vec of Bars. + let bar = Bar; + let f1 = Fat { ptr: [bar, bar, bar] }; + foo2(&f1); + let f2 = &f1; + foo2(f2); + let f3: &Fat<[Bar]> = f2; + foo2(f3); + let f4: &Fat<[Bar]> = &f1; + foo2(f4); + let f5: &Fat<[Bar]> = &Fat { ptr: [bar, bar, bar] }; + foo2(f5); + + // Assignment. + let f5: &mut Fat<[int]> = &mut Fat { ptr: [1, 2, 3] }; + f5.ptr[1] = 34; + assert!(f5.ptr[0] == 1); + assert!(f5.ptr[1] == 34); + assert!(f5.ptr[2] == 3); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { ptr: [] }; + assert!(f5.ptr.len() == 0); + let f5: &Fat<[Bar]> = &Fat { ptr: [] }; + assert!(f5.ptr.len() == 0); +} diff --git a/src/test/run-pass/dst-struct.rs b/src/test/run-pass/dst-struct.rs new file mode 100644 index 0000000000000..6b8e25e85590f --- /dev/null +++ b/src/test/run-pass/dst-struct.rs @@ -0,0 +1,127 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +// x is a fat pointer +fn foo(x: &Fat<[int]>) { + let y = &x.ptr; + assert!(x.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr[1] == 2); + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); +} + +fn foo2(x: &Fat<[T]>) { + let y = &x.ptr; + let bar = Bar; + assert!(x.ptr.len() == 3); + assert!(y[0].to_bar() == bar); + assert!(x.ptr[1].to_bar() == bar); + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); +} + +fn foo3(x: &Fat>) { + let y = &x.ptr.ptr; + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.f1 == 8); + assert!(x.ptr.f2 == "deep str"); + assert!(x.ptr.ptr.len() == 3); + assert!(y[0] == 1); + assert!(x.ptr.ptr[1] == 2); +} + + +#[deriving(PartialEq,Eq)] +struct Bar; + +trait ToBar { + fn to_bar(&self) -> Bar; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } +} + +pub fn main() { + // With a vec of ints. + let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat<[int]> = f2; + foo(f3); + let f4: &Fat<[int]> = &f1; + foo(f4); + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(f5); + + // With a vec of Bars. + let bar = Bar; + let f1 = Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(&f1); + let f2 = &f1; + foo2(f2); + let f3: &Fat<[Bar]> = f2; + foo2(f3); + let f4: &Fat<[Bar]> = &f1; + foo2(f4); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [bar, bar, bar] }; + foo2(f5); + + // Assignment. + let f5: &mut Fat<[int]> = &mut Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + f5.ptr[1] = 34; + assert!(f5.ptr[0] == 1); + assert!(f5.ptr[1] == 34); + assert!(f5.ptr[2] == 3); + + // Zero size vec. + let f5: &Fat<[int]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.len() == 0); + let f5: &Fat<[Bar]> = &Fat { f1: 5, f2: "some str", ptr: [] }; + assert!(f5.ptr.len() == 0); + + // Deeply nested. + let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(&f1); + let f2 = &f1; + foo3(f2); + let f3: &Fat> = f2; + foo3(f3); + let f4: &Fat> = &f1; + foo3(f4); + let f5: &Fat> = + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + foo3(f5); + + // Box. + let f1 = box [1i, 2, 3]; + assert!((*f1)[1] == 2); + let f2: Box<[int]> = f1; + assert!((*f2)[1] == 2); + + // Nested Box. + let f1 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f1); + let f2 : Box> = f1; + foo(&*f2); + let f3 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f3); +} diff --git a/src/test/run-pass/dst-trait.rs b/src/test/run-pass/dst-trait.rs new file mode 100644 index 0000000000000..9762730955104 --- /dev/null +++ b/src/test/run-pass/dst-trait.rs @@ -0,0 +1,111 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Fat { + f1: int, + f2: &'static str, + ptr: T +} + +#[deriving(PartialEq,Eq)] +struct Bar; + +#[deriving(PartialEq,Eq)] +struct Bar1 { + f: int +} + +trait ToBar { + fn to_bar(&self) -> Bar; + fn to_val(&self) -> int; +} + +impl ToBar for Bar { + fn to_bar(&self) -> Bar { + *self + } + fn to_val(&self) -> int { + 0 + } +} +impl ToBar for Bar1 { + fn to_bar(&self) -> Bar { + Bar + } + fn to_val(&self) -> int { + self.f + } +} + +// x is a fat pointer +fn foo(x: &Fat) { + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.to_bar() == Bar); + assert!(x.ptr.to_val() == 42); + + let y = &x.ptr; + assert!(y.to_bar() == Bar); + assert!(y.to_val() == 42); +} + +fn bar(x: &ToBar) { + assert!(x.to_bar() == Bar); + assert!(x.to_val() == 42); +} + +fn baz(x: &Fat>) { + assert!(x.f1 == 5); + assert!(x.f2 == "some str"); + assert!(x.ptr.f1 == 8); + assert!(x.ptr.f2 == "deep str"); + assert!(x.ptr.ptr.to_bar() == Bar); + assert!(x.ptr.ptr.to_val() == 42); + + let y = &x.ptr.ptr; + assert!(y.to_bar() == Bar); + assert!(y.to_val() == 42); + +} + +pub fn main() { + let f1 = Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + foo(&f1); + let f2 = &f1; + foo(f2); + let f3: &Fat = f2; + foo(f3); + let f4: &Fat = &f1; + foo(f4); + let f5: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar1 {f :42} }; + foo(f5); + + // Zero size object. + let f6: &Fat = &Fat { f1: 5, f2: "some str", ptr: Bar }; + assert!(f6.ptr.to_bar() == Bar); + + // &* + let f7: Box = box Bar1 {f :42}; + bar(&*f7); + + // Deep nesting + let f1 = + Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} }; + baz(&f1); + let f2 = &f1; + baz(f2); + let f3: &Fat> = f2; + baz(f3); + let f4: &Fat> = &f1; + baz(f4); + let f5: &Fat> = + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: Bar1 {f :42}} }; + baz(f5); +} diff --git a/src/test/run-pass/evec-slice.rs b/src/test/run-pass/evec-slice.rs index 9c5995b7ba010..4a112f145c3ed 100644 --- a/src/test/run-pass/evec-slice.rs +++ b/src/test/run-pass/evec-slice.rs @@ -14,7 +14,7 @@ extern crate debug; pub fn main() { let x : &[int] = &[1,2,3,4,5]; - let mut z = &[1,2,3,4,5]; + let mut z : &[int] = &[1,2,3,4,5]; z = x; assert_eq!(z[0], 1); assert_eq!(z[4], 5); diff --git a/src/test/run-pass/gc-vec.rs b/src/test/run-pass/gc-vec.rs new file mode 100644 index 0000000000000..430ee16bc8a26 --- /dev/null +++ b/src/test/run-pass/gc-vec.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::gc::{GC}; + +fn main() { + // A fixed-size array allocated in a garbage-collected box + let x = box(GC) [1i, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(x[0], 1); + assert_eq!(x[6], 7); + assert_eq!(x[9], 10); + + let y = x; + assert!(*y == [1i, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +} diff --git a/src/test/run-pass/issue-14936.rs b/src/test/run-pass/issue-14936.rs index 123ad36ee4f2d..0aca74c76c3e7 100644 --- a/src/test/run-pass/issue-14936.rs +++ b/src/test/run-pass/issue-14936.rs @@ -30,7 +30,8 @@ macro_rules! demo { : "r"(&wrap(y, "in", &mut history))); } assert_eq!((x,y), (1,1)); - assert_eq!(history.as_slice(), &["out", "in"]); + let b: &[_] = &["out", "in"]; + assert_eq!(history.as_slice(), b); } } } diff --git a/src/test/run-pass/issue-15080.rs b/src/test/run-pass/issue-15080.rs index b0741391d8039..444e8bd37707e 100644 --- a/src/test/run-pass/issue-15080.rs +++ b/src/test/run-pass/issue-15080.rs @@ -9,7 +9,7 @@ // except according to those terms. fn main() { - let mut x = &[1i, 2, 3, 4]; + let mut x: &[_] = &[1i, 2, 3, 4]; let mut result = vec!(); loop { diff --git a/src/test/run-pass/issue-7012.rs b/src/test/run-pass/issue-7012.rs index 4e74a7a1ecfe0..96db28f4a101f 100644 --- a/src/test/run-pass/issue-7012.rs +++ b/src/test/run-pass/issue-7012.rs @@ -22,6 +22,7 @@ static test1: signature<'static> = signature { }; pub fn main() { - let test = &[0x243f6a88u32,0x85a308d3u32,0x13198a2eu32,0x03707344u32,0xa4093822u32,0x299f31d0u32]; + let test: &[u32] = &[0x243f6a88u32,0x85a308d3u32,0x13198a2eu32, + 0x03707344u32,0xa4093822u32,0x299f31d0u32]; println!("{}",test==test1.pattern); } diff --git a/src/test/run-pass/issue-9259.rs b/src/test/run-pass/issue-9259.rs index 35f51efe135ca..2818b8249692a 100644 --- a/src/test/run-pass/issue-9259.rs +++ b/src/test/run-pass/issue-9259.rs @@ -14,7 +14,7 @@ struct A<'a> { } pub fn main() { - let b = &["foo".to_string()]; + let b: &[String] = &["foo".to_string()]; let a = A { a: &["test".to_string()], b: Some(b), diff --git a/src/test/run-pass/match-vec-alternatives.rs b/src/test/run-pass/match-vec-alternatives.rs index ffbc4e85cb685..de1bb02bfefc6 100644 --- a/src/test/run-pass/match-vec-alternatives.rs +++ b/src/test/run-pass/match-vec-alternatives.rs @@ -68,15 +68,21 @@ fn main() { assert_eq!(match_vecs_snoc::(&[], &[]), "both empty"); assert_eq!(match_vecs_snoc(&[1i, 2, 3], &[]), "one empty"); - assert_eq!(match_nested_vecs_cons(None, Ok(&[4u, 2u])), "None, Ok(at least two elements)"); + assert_eq!(match_nested_vecs_cons(None, Ok::<&[_], ()>(&[4u, 2u])), + "None, Ok(at least two elements)"); assert_eq!(match_nested_vecs_cons::(None, Err(())), "None, Ok(less than one element)"); - assert_eq!(match_nested_vecs_cons::(Some(&[]), Ok(&[])), "Some(empty), Ok(empty)"); - assert_eq!(match_nested_vecs_cons(Some(&[1i]), Err(())), "Some(non-empty), any"); - assert_eq!(match_nested_vecs_cons(Some(&[(42i, ())]), Ok(&[(1i, ())])), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_cons::(Some::<&[_]>(&[]), Ok::<&[_], ()>(&[])), + "Some(empty), Ok(empty)"); + assert_eq!(match_nested_vecs_cons(Some::<&[_]>(&[1i]), Err(())), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_cons(Some::<&[_]>(&[(42i, ())]), Ok::<&[_], ()>(&[(1i, ())])), + "Some(non-empty), any"); - assert_eq!(match_nested_vecs_snoc(None, Ok(&[4u, 2u])), "None, Ok(at least two elements)"); + assert_eq!(match_nested_vecs_snoc(None, Ok::<&[_], ()>(&[4u, 2u])), + "None, Ok(at least two elements)"); assert_eq!(match_nested_vecs_snoc::(None, Err(())), "None, Ok(less than one element)"); - assert_eq!(match_nested_vecs_snoc::(Some(&[]), Ok(&[])), "Some(empty), Ok(empty)"); - assert_eq!(match_nested_vecs_snoc(Some(&[1i]), Err(())), "Some(non-empty), any"); - assert_eq!(match_nested_vecs_snoc(Some(&[(42i, ())]), Ok(&[(1i, ())])), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_snoc::(Some::<&[_]>(&[]), Ok::<&[_], ()>(&[])), + "Some(empty), Ok(empty)"); + assert_eq!(match_nested_vecs_snoc(Some::<&[_]>(&[1i]), Err(())), "Some(non-empty), any"); + assert_eq!(match_nested_vecs_snoc(Some::<&[_]>(&[(42i, ())]), Ok::<&[_], ()>(&[(1i, ())])), + "Some(non-empty), any"); } diff --git a/src/test/run-pass/order-drop-with-match.rs b/src/test/run-pass/order-drop-with-match.rs index ed5cff36c8bb2..9a76beac9e5f7 100644 --- a/src/test/run-pass/order-drop-with-match.rs +++ b/src/test/run-pass/order-drop-with-match.rs @@ -59,6 +59,7 @@ fn main() { } } unsafe { - assert_eq!(&[1, 2, 3], ORDER.as_slice()); + let expected: &[_] = &[1, 2, 3]; + assert_eq!(expected, ORDER.as_slice()); } } diff --git a/src/test/run-pass/overloaded-deref-count.rs b/src/test/run-pass/overloaded-deref-count.rs index 0b5406b8f67d5..2d54663993925 100644 --- a/src/test/run-pass/overloaded-deref-count.rs +++ b/src/test/run-pass/overloaded-deref-count.rs @@ -81,5 +81,6 @@ pub fn main() { // Check the final states. assert_eq!(*n, 2); - assert_eq!((*v).as_slice(), &[1, 2]); + let expected: &[_] = &[1, 2]; + assert_eq!((*v).as_slice(), expected); } diff --git a/src/test/run-pass/reflect-visit-type.rs b/src/test/run-pass/reflect-visit-type.rs index 596e56b424a30..f599a2b7ad55c 100644 --- a/src/test/run-pass/reflect-visit-type.rs +++ b/src/test/run-pass/reflect-visit-type.rs @@ -61,6 +61,8 @@ impl TyVisitor for MyVisitor { fn visit_char(&mut self) -> bool { true } fn visit_estr_slice(&mut self) -> bool { true } + // NOTE: remove after snapshot + #[cfg(stage0)] fn visit_estr_fixed(&mut self, _sz: uint, _sz2: uint, _align: uint) -> bool { true } @@ -72,7 +74,7 @@ impl TyVisitor for MyVisitor { fn visit_evec_slice(&mut self, _mtbl: uint, _inner: *const TyDesc) -> bool { true } fn visit_evec_fixed(&mut self, _n: uint, _sz: uint, _align: uint, - _mtbl: uint, _inner: *const TyDesc) -> bool { true } + _inner: *const TyDesc) -> bool { true } fn visit_enter_rec(&mut self, _n_fields: uint, _sz: uint, _align: uint) -> bool { true } diff --git a/src/test/run-pass/running-with-no-runtime.rs b/src/test/run-pass/running-with-no-runtime.rs index 44435dc2398dc..3f559df4b7e7a 100644 --- a/src/test/run-pass/running-with-no-runtime.rs +++ b/src/test/run-pass/running-with-no-runtime.rs @@ -43,14 +43,22 @@ fn main() { let args = os::args(); let me = args.get(0).as_slice(); - pass(Command::new(me).arg(&[1u8]).output().unwrap()); - pass(Command::new(me).arg(&[2u8]).output().unwrap()); - pass(Command::new(me).arg(&[3u8]).output().unwrap()); - pass(Command::new(me).arg(&[4u8]).output().unwrap()); - pass(Command::new(me).arg(&[5u8]).output().unwrap()); - pass(Command::new(me).arg(&[6u8]).output().unwrap()); - pass(Command::new(me).arg(&[7u8]).output().unwrap()); - pass(Command::new(me).arg(&[8u8]).output().unwrap()); + let x: &[u8] = &[1u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[2u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[3u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[4u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[5u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[6u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[7u8]; + pass(Command::new(me).arg(x).output().unwrap()); + let x: &[u8] = &[8u8]; + pass(Command::new(me).arg(x).output().unwrap()); } fn pass(output: ProcessOutput) { diff --git a/src/test/run-pass/smallest-hello-world.rs b/src/test/run-pass/smallest-hello-world.rs index 4f1a3817fabd7..52e7118653766 100644 --- a/src/test/run-pass/smallest-hello-world.rs +++ b/src/test/run-pass/smallest-hello-world.rs @@ -22,6 +22,7 @@ extern "rust-intrinsic" { fn transmute(t: T) -> U; } #[lang = "stack_exhausted"] extern fn stack_exhausted() {} #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "sized"] pub trait Sized {} #[start] #[no_split_stack] diff --git a/src/test/run-pass/syntax-extension-bytes.rs b/src/test/run-pass/syntax-extension-bytes.rs index 5b66d5f28a926..8d5333e5b3fc5 100644 --- a/src/test/run-pass/syntax-extension-bytes.rs +++ b/src/test/run-pass/syntax-extension-bytes.rs @@ -12,13 +12,17 @@ static static_vec: &'static [u8] = bytes!("abc", 0xFF, '!'); pub fn main() { let vec = bytes!("abc"); - assert_eq!(vec, &[97_u8, 98_u8, 99_u8]); + let expected: &[u8] = &[97_u8, 98_u8, 99_u8]; + assert_eq!(vec, expected); let vec = bytes!("null", 0); - assert_eq!(vec, &[110_u8, 117_u8, 108_u8, 108_u8, 0_u8]); + let expected: &[u8] = &[110_u8, 117_u8, 108_u8, 108_u8, 0_u8]; + assert_eq!(vec, expected); let vec = bytes!(' ', " ", 32, 32u8); - assert_eq!(vec, &[32_u8, 32_u8, 32_u8, 32_u8]); + let expected: &[u8] = &[32_u8, 32_u8, 32_u8, 32_u8]; + assert_eq!(vec, expected); - assert_eq!(static_vec, &[97_u8, 98_u8, 99_u8, 255_u8, 33_u8]); + let expected: &[u8] = &[97_u8, 98_u8, 99_u8, 255_u8, 33_u8]; + assert_eq!(static_vec, expected); } diff --git a/src/test/run-pass/typeck_type_placeholder_1.rs b/src/test/run-pass/typeck_type_placeholder_1.rs index f95e9ad7d83c9..10c91274f10f8 100644 --- a/src/test/run-pass/typeck_type_placeholder_1.rs +++ b/src/test/run-pass/typeck_type_placeholder_1.rs @@ -15,10 +15,11 @@ static CONSTEXPR: *const int = &413 as *const _; pub fn main() { let x: Vec<_> = range(0u, 5).collect(); - assert_eq!(x.as_slice(), &[0u,1,2,3,4]); + let expected: &[uint] = &[0,1,2,3,4]; + assert_eq!(x.as_slice(), expected); let x = range(0u, 5).collect::>(); - assert_eq!(x.as_slice(), &[0u,1,2,3,4]); + assert_eq!(x.as_slice(), expected); let y: _ = "hello"; assert_eq!(y.len(), 5); diff --git a/src/test/run-pass/vec-dst.rs b/src/test/run-pass/vec-dst.rs new file mode 100644 index 0000000000000..809dde38eb498 --- /dev/null +++ b/src/test/run-pass/vec-dst.rs @@ -0,0 +1,115 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate debug; + +fn reflect() { + // Tests for reflective printing. + // Also tests drop glue. + let x = [1, 2, 3, 4]; + let x2 = [(), (), ()]; + let e1: [uint, ..0] = []; + let e2: [&'static str, ..0] = []; + let e3: [(), ..0] = []; + assert!(format!("{:?}", x) == "[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", x2) == "[(), (), ()]".to_string()); + assert!(format!("{:?}", e1) == "[]".to_string()); + assert!(format!("{:?}", e2) == "[]".to_string()); + assert!(format!("{:?}", e3) == "[]".to_string()); + + let rx: &[uint, ..4] = &x; + let rx2: &[(), ..3] = &x2; + let re1: &[uint, ..0] = &e1; + let re2: &[&'static str, ..0] = &e2; + let re3: &[(), ..0] = &e3; + assert!(format!("{:?}", rx) == "&[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "&[(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "&[]".to_string()); + assert!(format!("{:?}", re2) == "&[]".to_string()); + assert!(format!("{:?}", re3) == "&[]".to_string()); + + let rx: &[uint] = &x; + let rx2: &[()] = &x2; + let re1: &[uint] = &e1; + let re2: &[&'static str] = &e2; + let re3: &[()] = &e3; + assert!(format!("{:?}", rx) == "&[1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "&[(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "&[]".to_string()); + assert!(format!("{:?}", re2) == "&[]".to_string()); + assert!(format!("{:?}", re3) == "&[]".to_string()); + + // FIXME(15049) These should all work some day. + /*let rx: Box<[uint, ..4]> = box x; + let rx2: Box<[(), ..3]> = box x2; + let re1: Box<[uint, ..0]> = box e1; + let re2: Box<[&'static str, ..0]> = box e2; + let re3: Box<[(), ..0]> = box e3; + assert!(format!("{:?}", rx) == "box [1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "box [(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "box []".to_string()); + assert!(format!("{:?}", re2) == "box []".to_string()); + assert!(format!("{:?}", re3) == "box []".to_string()); + + let x = [1, 2, 3, 4]; + let x2 = [(), (), ()]; + let e1: [uint, ..0] = []; + let e2: [&'static str, ..0] = []; + let e3: [(), ..0] = []; + let rx: Box<[uint]> = box x; + let rx2: Box<[()]> = box x2; + let re1: Box<[uint]> = box e1; + let re2: Box<[&'static str]> = box e2; + let re3: Box<[()]> = box e3; + assert!(format!("{:?}", rx) == "box [1u, 2u, 3u, 4u]".to_string()); + assert!(format!("{:?}", rx2) == "box [(), (), ()]".to_string()); + assert!(format!("{:?}", re1) == "box []".to_string()); + assert!(format!("{:?}", re2) == "box []".to_string()); + assert!(format!("{:?}", re3) == "box []".to_string());*/ +} + +fn sub_expr() { + // Test for a &[T] => &&[T] coercion in sub-expression position + // (surpisingly, this can cause errors which are not caused by either of: + // `let x = vec.mut_slice(0, 2);` + // `foo(vec.mut_slice(0, 2));` ). + let mut vec: Vec = vec!(1, 2, 3, 4); + let b: &mut [int] = [1, 2]; + assert!(vec.mut_slice(0, 2) == b); +} + +fn index() { + // Tests for indexing into box/& [T, ..n] + let x: [int, ..3] = [1, 2, 3]; + let mut x: Box<[int, ..3]> = box x; + assert!(x[0] == 1); + assert!(x[1] == 2); + assert!(x[2] == 3); + x[1] = 45; + assert!(x[0] == 1); + assert!(x[1] == 45); + assert!(x[2] == 3); + + let mut x: [int, ..3] = [1, 2, 3]; + let x: &mut [int, ..3] = &mut x; + assert!(x[0] == 1); + assert!(x[1] == 2); + assert!(x[2] == 3); + x[1] = 45; + assert!(x[0] == 1); + assert!(x[1] == 45); + assert!(x[2] == 3); +} + +pub fn main() { + reflect(); + sub_expr(); + index(); +} diff --git a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs index c070e5dab77d0..2fd8a4ab256fd 100644 --- a/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs +++ b/src/test/run-pass/vec-matching-legal-tail-element-borrow.rs @@ -10,6 +10,7 @@ pub fn main() { let x = &[1i, 2, 3, 4, 5]; + let x: &[int] = &[1, 2, 3, 4, 5]; if !x.is_empty() { let el = match x { [1, ..ref tail] => &tail[0], diff --git a/src/test/run-pass/vec-matching.rs b/src/test/run-pass/vec-matching.rs index 8ba8ba4482edc..e95495a42d282 100644 --- a/src/test/run-pass/vec-matching.rs +++ b/src/test/run-pass/vec-matching.rs @@ -23,12 +23,14 @@ fn b() { [a, b, ..c] => { assert_eq!(a, 1); assert_eq!(b, 2); - assert_eq!(c, &[3]); + let expected: &[_] = &[3]; + assert_eq!(c, expected); } } match x { [..a, b, c] => { - assert_eq!(a, &[1]); + let expected: &[_] = &[1]; + assert_eq!(a, expected); assert_eq!(b, 2); assert_eq!(c, 3); } @@ -36,7 +38,8 @@ fn b() { match x { [a, ..b, c] => { assert_eq!(a, 1); - assert_eq!(b, &[2]); + let expected: &[_] = &[2]; + assert_eq!(b, expected); assert_eq!(c, 3); } } @@ -69,7 +72,8 @@ fn d() { } fn e() { - match &[1i, 2, 3] { + let x: &[int] = &[1i, 2, 3]; + match x { [1, 2] => (), [..] => () } diff --git a/src/test/run-pass/vec-to_str.rs b/src/test/run-pass/vec-to_str.rs index deb08a4608cc0..52e0ba89479f5 100644 --- a/src/test/run-pass/vec-to_str.rs +++ b/src/test/run-pass/vec-to_str.rs @@ -10,10 +10,9 @@ pub fn main() { assert_eq!((vec!(0i, 1)).to_string(), "[0, 1]".to_string()); - assert_eq!((&[1i, 2]).to_string(), "[1, 2]".to_string()); let foo = vec!(3i, 4); - let bar = &[4i, 5]; + let bar: &[int] = &[4, 5]; assert_eq!(foo.to_string(), "[3, 4]".to_string()); assert_eq!(bar.to_string(), "[4, 5]".to_string());