diff --git a/src/liballoc/benches/btree/set.rs b/src/liballoc/benches/btree/set.rs index 08e1db5fbb74d..6357ea3ea11bd 100644 --- a/src/liballoc/benches/btree/set.rs +++ b/src/liballoc/benches/btree/set.rs @@ -3,59 +3,49 @@ use std::collections::BTreeSet; use rand::{thread_rng, Rng}; use test::{black_box, Bencher}; -fn random(n1: u32, n2: u32) -> [BTreeSet; 2] { +fn random(n: usize) -> BTreeSet { let mut rng = thread_rng(); - let mut set1 = BTreeSet::new(); - let mut set2 = BTreeSet::new(); - for _ in 0..n1 { - let i = rng.gen::(); - set1.insert(i); + let mut set = BTreeSet::new(); + while set.len() < n { + set.insert(rng.gen()); } - for _ in 0..n2 { - let i = rng.gen::(); - set2.insert(i); - } - [set1, set2] + assert_eq!(set.len(), n); + set } -fn staggered(n1: u32, n2: u32) -> [BTreeSet; 2] { - let mut even = BTreeSet::new(); - let mut odd = BTreeSet::new(); - for i in 0..n1 { - even.insert(i * 2); - } - for i in 0..n2 { - odd.insert(i * 2 + 1); +fn neg(n: usize) -> BTreeSet { + let mut set = BTreeSet::new(); + for i in -(n as i32)..=-1 { + set.insert(i); } - [even, odd] + assert_eq!(set.len(), n); + set } -fn neg_vs_pos(n1: u32, n2: u32) -> [BTreeSet; 2] { - let mut neg = BTreeSet::new(); - let mut pos = BTreeSet::new(); - for i in -(n1 as i32)..=-1 { - neg.insert(i); - } - for i in 1..=(n2 as i32) { - pos.insert(i); +fn pos(n: usize) -> BTreeSet { + let mut set = BTreeSet::new(); + for i in 1..=(n as i32) { + set.insert(i); } - [neg, pos] + assert_eq!(set.len(), n); + set } -fn pos_vs_neg(n1: u32, n2: u32) -> [BTreeSet; 2] { - let mut neg = BTreeSet::new(); - let mut pos = BTreeSet::new(); - for i in -(n1 as i32)..=-1 { - neg.insert(i); - } - for i in 1..=(n2 as i32) { - pos.insert(i); + +fn stagger(n1: usize, factor: usize) -> [BTreeSet; 2] { + let n2 = n1 * factor; + let mut sets = [BTreeSet::new(), BTreeSet::new()]; + for i in 0..(n1 + n2) { + let b = i % (factor + 1) != 0; + sets[b as usize].insert(i as u32); } - [pos, neg] + assert_eq!(sets[0].len(), n1); + assert_eq!(sets[1].len(), n2); + sets } -macro_rules! set_intersection_bench { - ($name: ident, $sets: expr) => { +macro_rules! set_bench { + ($name: ident, $set_func: ident, $result_func: ident, $sets: expr) => { #[bench] pub fn $name(b: &mut Bencher) { // setup @@ -63,26 +53,36 @@ macro_rules! set_intersection_bench { // measure b.iter(|| { - let x = sets[0].intersection(&sets[1]).count(); + let x = sets[0].$set_func(&sets[1]).$result_func(); black_box(x); }) } }; } -set_intersection_bench! {intersect_random_100, random(100, 100)} -set_intersection_bench! {intersect_random_10k, random(10_000, 10_000)} -set_intersection_bench! {intersect_random_10_vs_10k, random(10, 10_000)} -set_intersection_bench! {intersect_random_10k_vs_10, random(10_000, 10)} -set_intersection_bench! {intersect_staggered_100, staggered(100, 100)} -set_intersection_bench! {intersect_staggered_10k, staggered(10_000, 10_000)} -set_intersection_bench! {intersect_staggered_10_vs_10k, staggered(10, 10_000)} -set_intersection_bench! {intersect_staggered_10k_vs_10, staggered(10_000, 10)} -set_intersection_bench! {intersect_neg_vs_pos_100, neg_vs_pos(100, 100)} -set_intersection_bench! {intersect_neg_vs_pos_10k, neg_vs_pos(10_000, 10_000)} -set_intersection_bench! {intersect_neg_vs_pos_10_vs_10k,neg_vs_pos(10, 10_000)} -set_intersection_bench! {intersect_neg_vs_pos_10k_vs_10,neg_vs_pos(10_000, 10)} -set_intersection_bench! {intersect_pos_vs_neg_100, pos_vs_neg(100, 100)} -set_intersection_bench! {intersect_pos_vs_neg_10k, pos_vs_neg(10_000, 10_000)} -set_intersection_bench! {intersect_pos_vs_neg_10_vs_10k,pos_vs_neg(10, 10_000)} -set_intersection_bench! {intersect_pos_vs_neg_10k_vs_10,pos_vs_neg(10_000, 10)} +set_bench! {intersection_100_neg_vs_100_pos, intersection, count, [neg(100), pos(100)]} +set_bench! {intersection_100_neg_vs_10k_pos, intersection, count, [neg(100), pos(10_000)]} +set_bench! {intersection_100_pos_vs_100_neg, intersection, count, [pos(100), neg(100)]} +set_bench! {intersection_100_pos_vs_10k_neg, intersection, count, [pos(100), neg(10_000)]} +set_bench! {intersection_10k_neg_vs_100_pos, intersection, count, [neg(10_000), pos(100)]} +set_bench! {intersection_10k_neg_vs_10k_pos, intersection, count, [neg(10_000), pos(10_000)]} +set_bench! {intersection_10k_pos_vs_100_neg, intersection, count, [pos(10_000), neg(100)]} +set_bench! {intersection_10k_pos_vs_10k_neg, intersection, count, [pos(10_000), neg(10_000)]} +set_bench! {intersection_random_100_vs_100, intersection, count, [random(100), random(100)]} +set_bench! {intersection_random_100_vs_10k, intersection, count, [random(100), random(10_000)]} +set_bench! {intersection_random_10k_vs_100, intersection, count, [random(10_000), random(100)]} +set_bench! {intersection_random_10k_vs_10k, intersection, count, [random(10_000), random(10_000)]} +set_bench! {intersection_staggered_100_vs_100, intersection, count, stagger(100, 1)} +set_bench! {intersection_staggered_10k_vs_10k, intersection, count, stagger(10_000, 1)} +set_bench! {intersection_staggered_100_vs_10k, intersection, count, stagger(100, 100)} +set_bench! {difference_random_100_vs_100, difference, count, [random(100), random(100)]} +set_bench! {difference_random_100_vs_10k, difference, count, [random(100), random(10_000)]} +set_bench! {difference_random_10k_vs_100, difference, count, [random(10_000), random(100)]} +set_bench! {difference_random_10k_vs_10k, difference, count, [random(10_000), random(10_000)]} +set_bench! {difference_staggered_100_vs_100, difference, count, stagger(100, 1)} +set_bench! {difference_staggered_10k_vs_10k, difference, count, stagger(10_000, 1)} +set_bench! {difference_staggered_100_vs_10k, difference, count, stagger(100, 100)} +set_bench! {is_subset_100_vs_100, is_subset, clone, [pos(100), pos(100)]} +set_bench! {is_subset_100_vs_10k, is_subset, clone, [pos(100), pos(10_000)]} +set_bench! {is_subset_10k_vs_100, is_subset, clone, [pos(10_000), pos(100)]} +set_bench! {is_subset_10k_vs_10k, is_subset, clone, [pos(10_000), pos(10_000)]} diff --git a/src/liballoc/collections/btree/set.rs b/src/liballoc/collections/btree/set.rs index 2be6455ad5903..e71767077ca55 100644 --- a/src/liballoc/collections/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -3,7 +3,7 @@ use core::borrow::Borrow; use core::cmp::Ordering::{self, Less, Greater, Equal}; -use core::cmp::{min, max}; +use core::cmp::max; use core::fmt::{self, Debug}; use core::iter::{Peekable, FromIterator, FusedIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; @@ -118,17 +118,36 @@ pub struct Range<'a, T: 'a> { /// [`difference`]: struct.BTreeSet.html#method.difference #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a> { - a: Peekable>, - b: Peekable>, + inner: DifferenceInner<'a, T>, +} +enum DifferenceInner<'a, T: 'a> { + Stitch { + self_iter: Iter<'a, T>, + other_iter: Peekable>, + }, + Search { + self_iter: Iter<'a, T>, + other_set: &'a BTreeSet, + }, } #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Difference<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Difference") - .field(&self.a) - .field(&self.b) - .finish() + match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => f + .debug_tuple("Difference") + .field(&self_iter) + .field(&other_iter) + .finish(), + DifferenceInner::Search { + self_iter, + other_set: _, + } => f.debug_tuple("Difference").field(&self_iter).finish(), + } } } @@ -164,17 +183,36 @@ impl fmt::Debug for SymmetricDifference<'_, T> { /// [`intersection`]: struct.BTreeSet.html#method.intersection #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a> { - a: Peekable>, - b: Peekable>, + inner: IntersectionInner<'a, T>, +} +enum IntersectionInner<'a, T: 'a> { + Stitch { + small_iter: Iter<'a, T>, // for size_hint, should be the smaller of the sets + other_iter: Iter<'a, T>, + }, + Search { + small_iter: Iter<'a, T>, + large_set: &'a BTreeSet, + }, } #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Intersection<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Intersection") - .field(&self.a) - .field(&self.b) - .finish() + match &self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => f + .debug_tuple("Intersection") + .field(&small_iter) + .field(&other_iter) + .finish(), + IntersectionInner::Search { + small_iter, + large_set: _, + } => f.debug_tuple("Intersection").field(&small_iter).finish(), + } } } @@ -201,6 +239,14 @@ impl fmt::Debug for Union<'_, T> { } } +// This constant is used by functions that compare two sets. +// It estimates the relative size at which searching performs better +// than iterating, based on the benchmarks in +// https://github.com/ssomers/rust_bench_btreeset_intersection; +// It's used to divide rather than multiply sizes, to rule out overflow, +// and it's a power of two to make that division cheap. +const ITER_PERFORMANCE_TIPPING_SIZE_DIFF: usize = 16; + impl BTreeSet { /// Makes a new `BTreeSet` with a reasonable choice of B. /// @@ -268,9 +314,24 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn difference<'a>(&'a self, other: &'a BTreeSet) -> Difference<'a, T> { - Difference { - a: self.iter().peekable(), - b: other.iter().peekable(), + if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Self is bigger than or not much smaller than other set. + // Iterate both sets jointly, spotting matches along the way. + Difference { + inner: DifferenceInner::Stitch { + self_iter: self.iter(), + other_iter: other.iter().peekable(), + }, + } + } else { + // Self is much smaller than other set, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + Difference { + inner: DifferenceInner::Search { + self_iter: self.iter(), + other_set: other, + }, + } } } @@ -326,9 +387,29 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn intersection<'a>(&'a self, other: &'a BTreeSet) -> Intersection<'a, T> { - Intersection { - a: self.iter().peekable(), - b: other.iter().peekable(), + let (small, other) = if self.len() <= other.len() { + (self, other) + } else { + (other, self) + }; + if small.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Small set is not much smaller than other set. + // Iterate both sets jointly, spotting matches along the way. + Intersection { + inner: IntersectionInner::Stitch { + small_iter: small.iter(), + other_iter: other.iter(), + }, + } + } else { + // Big difference in number of elements, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + Intersection { + inner: IntersectionInner::Search { + small_iter: small.iter(), + large_set: other, + }, + } } } @@ -462,28 +543,44 @@ impl BTreeSet { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_subset(&self, other: &BTreeSet) -> bool { - // Stolen from TreeMap - let mut x = self.iter(); - let mut y = other.iter(); - let mut a = x.next(); - let mut b = y.next(); - while a.is_some() { - if b.is_none() { - return false; - } + // Same result as self.difference(other).next().is_none() + // but the 3 paths below are faster (in order: hugely, 20%, 5%). + if self.len() > other.len() { + false + } else if self.len() > other.len() / ITER_PERFORMANCE_TIPPING_SIZE_DIFF { + // Self is not much smaller than other set. + // Stolen from TreeMap + let mut x = self.iter(); + let mut y = other.iter(); + let mut a = x.next(); + let mut b = y.next(); + while a.is_some() { + if b.is_none() { + return false; + } - let a1 = a.unwrap(); - let b1 = b.unwrap(); + let a1 = a.unwrap(); + let b1 = b.unwrap(); - match b1.cmp(a1) { - Less => (), - Greater => return false, - Equal => a = x.next(), - } + match b1.cmp(a1) { + Less => (), + Greater => return false, + Equal => a = x.next(), + } - b = y.next(); + b = y.next(); + } + true + } else { + // Big difference in number of elements, or both sets are empty. + // Iterate the small set, searching for matches in the large set. + for next in self { + if !other.contains(next) { + return false; + } + } + true } - true } /// Returns `true` if the set is a superset of another, @@ -1001,8 +1098,22 @@ fn cmp_opt(x: Option<&T>, y: Option<&T>, short: Ordering, long: Ordering impl Clone for Difference<'_, T> { fn clone(&self) -> Self { Difference { - a: self.a.clone(), - b: self.b.clone(), + inner: match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => DifferenceInner::Stitch { + self_iter: self_iter.clone(), + other_iter: other_iter.clone(), + }, + DifferenceInner::Search { + self_iter, + other_set, + } => DifferenceInner::Search { + self_iter: self_iter.clone(), + other_set, + }, + }, } } } @@ -1011,24 +1122,52 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - loop { - match cmp_opt(self.a.peek(), self.b.peek(), Less, Less) { - Less => return self.a.next(), - Equal => { - self.a.next(); - self.b.next(); - } - Greater => { - self.b.next(); + match &mut self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter, + } => { + let mut self_next = self_iter.next()?; + loop { + match other_iter + .peek() + .map_or(Less, |other_next| Ord::cmp(self_next, other_next)) + { + Less => return Some(self_next), + Equal => { + self_next = self_iter.next()?; + other_iter.next(); + } + Greater => { + other_iter.next(); + } + } } } + DifferenceInner::Search { + self_iter, + other_set, + } => loop { + let self_next = self_iter.next()?; + if !other_set.contains(&self_next) { + return Some(self_next); + } + }, } } fn size_hint(&self) -> (usize, Option) { - let a_len = self.a.len(); - let b_len = self.b.len(); - (a_len.saturating_sub(b_len), Some(a_len)) + let (self_len, other_len) = match &self.inner { + DifferenceInner::Stitch { + self_iter, + other_iter + } => (self_iter.len(), other_iter.len()), + DifferenceInner::Search { + self_iter, + other_set + } => (self_iter.len(), other_set.len()), + }; + (self_len.saturating_sub(other_len), Some(self_len)) } } @@ -1073,8 +1212,22 @@ impl FusedIterator for SymmetricDifference<'_, T> {} impl Clone for Intersection<'_, T> { fn clone(&self) -> Self { Intersection { - a: self.a.clone(), - b: self.b.clone(), + inner: match &self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => IntersectionInner::Stitch { + small_iter: small_iter.clone(), + other_iter: other_iter.clone(), + }, + IntersectionInner::Search { + small_iter, + large_set, + } => IntersectionInner::Search { + small_iter: small_iter.clone(), + large_set, + }, + }, } } } @@ -1083,24 +1236,39 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> { type Item = &'a T; fn next(&mut self) -> Option<&'a T> { - loop { - match Ord::cmp(self.a.peek()?, self.b.peek()?) { - Less => { - self.a.next(); - } - Equal => { - self.b.next(); - return self.a.next(); - } - Greater => { - self.b.next(); + match &mut self.inner { + IntersectionInner::Stitch { + small_iter, + other_iter, + } => { + let mut small_next = small_iter.next()?; + let mut other_next = other_iter.next()?; + loop { + match Ord::cmp(small_next, other_next) { + Less => small_next = small_iter.next()?, + Greater => other_next = other_iter.next()?, + Equal => return Some(small_next), + } } } + IntersectionInner::Search { + small_iter, + large_set, + } => loop { + let small_next = small_iter.next()?; + if large_set.contains(&small_next) { + return Some(small_next); + } + }, } } fn size_hint(&self) -> (usize, Option) { - (0, Some(min(self.a.len(), self.b.len()))) + let min_len = match &self.inner { + IntersectionInner::Stitch { small_iter, .. } => small_iter.len(), + IntersectionInner::Search { small_iter, .. } => small_iter.len(), + }; + (0, Some(min_len)) } } diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 4f5168f1ce572..d52814118b3c7 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -69,6 +69,20 @@ fn test_intersection() { check_intersection(&[11, 1, 3, 77, 103, 5, -5], &[2, 11, 77, -9, -42, 5, 3], &[3, 5, 11, 77]); + let large = (0..1000).collect::>(); + check_intersection(&[], &large, &[]); + check_intersection(&large, &[], &[]); + check_intersection(&[-1], &large, &[]); + check_intersection(&large, &[-1], &[]); + check_intersection(&[0], &large, &[0]); + check_intersection(&large, &[0], &[0]); + check_intersection(&[999], &large, &[999]); + check_intersection(&large, &[999], &[999]); + check_intersection(&[1000], &large, &[]); + check_intersection(&large, &[1000], &[]); + check_intersection(&[11, 5000, 1, 3, 77, 8924, 103], + &large, + &[1, 3, 11, 77, 103]); } #[test] @@ -84,6 +98,18 @@ fn test_difference() { check_difference(&[-5, 11, 22, 33, 40, 42], &[-12, -5, 14, 23, 34, 38, 39, 50], &[11, 22, 33, 40, 42]); + let large = (0..1000).collect::>(); + check_difference(&[], &large, &[]); + check_difference(&[-1], &large, &[-1]); + check_difference(&[0], &large, &[]); + check_difference(&[999], &large, &[]); + check_difference(&[1000], &large, &[1000]); + check_difference(&[11, 5000, 1, 3, 77, 8924, 103], + &large, + &[5000, 8924]); + check_difference(&large, &[], &large); + check_difference(&large, &[-1], &large); + check_difference(&large, &[1000], &large); } #[test] @@ -114,6 +140,41 @@ fn test_union() { &[-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]); } +#[test] +// Only tests the simple function definition with respect to intersection +fn test_is_disjoint() { + let one = [1].into_iter().collect::>(); + let two = [2].into_iter().collect::>(); + assert!(one.is_disjoint(&two)); +} + +#[test] +// Also tests the trivial function definition of is_superset +fn test_is_subset() { + fn is_subset(a: &[i32], b: &[i32]) -> bool { + let set_a = a.iter().collect::>(); + let set_b = b.iter().collect::>(); + set_a.is_subset(&set_b) + } + + assert_eq!(is_subset(&[], &[]), true); + assert_eq!(is_subset(&[], &[1, 2]), true); + assert_eq!(is_subset(&[0], &[1, 2]), false); + assert_eq!(is_subset(&[1], &[1, 2]), true); + assert_eq!(is_subset(&[2], &[1, 2]), true); + assert_eq!(is_subset(&[3], &[1, 2]), false); + assert_eq!(is_subset(&[1, 2], &[1]), false); + assert_eq!(is_subset(&[1, 2], &[1, 2]), true); + assert_eq!(is_subset(&[1, 2], &[2, 3]), false); + let large = (0..1000).collect::>(); + assert_eq!(is_subset(&[], &large), true); + assert_eq!(is_subset(&large, &[]), false); + assert_eq!(is_subset(&[-1], &large), false); + assert_eq!(is_subset(&[0], &large), true); + assert_eq!(is_subset(&[1, 2], &large), true); + assert_eq!(is_subset(&[999, 1000], &large), false); +} + #[test] fn test_zip() { let mut x = BTreeSet::new(); diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 4eb5bddb5d2f4..122ef9c79c276 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -1585,6 +1585,153 @@ impl [T] { sort::quicksort(self, |a, b| f(a).lt(&f(b))); } + /// Reorder the slice such that the element at `index` is at its final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index`. Additionally, this reordering is + /// unstable (i.e. any number of equal elements may end up at position `index`), in-place + /// (i.e. does not allocate), and `O(n)` worst-case. This function is also/ known as "kth + /// element" in other libraries. It returns a triplet of the following values: all elements less + /// than the one at the given index, the value at the given index, and all elements greater than + /// the one at the given index. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the median + /// v.partition_at_index(2); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [-3, -5, 1, 2, 4] || + /// v == [-5, -3, 1, 2, 4] || + /// v == [-3, -5, 1, 4, 2] || + /// v == [-5, -3, 1, 4, 2]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index(&mut self, index: usize) -> (&mut [T], &mut T, &mut [T]) + where T: Ord + { + let mut f = |a: &T, b: &T| a.lt(b); + sort::partition_at_index(self, index, &mut f) + } + + /// Reorder the slice with a comparator function such that the element at `index` is at its + /// final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index` using the comparator function. + /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at + /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// is also known as "kth element" in other libraries. It returns a triplet of the following + /// values: all elements less than the one at the given index, the value at the given index, + /// and all elements greater than the one at the given index, using the provided comparator + /// function. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Find the median as if the slice were sorted in descending order. + /// v.partition_at_index_by(2, |a, b| b.cmp(a)); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [2, 4, 1, -5, -3] || + /// v == [2, 4, 1, -3, -5] || + /// v == [4, 2, 1, -5, -3] || + /// v == [4, 2, 1, -3, -5]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index_by(&mut self, index: usize, mut compare: F) + -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T, &T) -> Ordering + { + let mut f = |a: &T, b: &T| compare(a, b) == Less; + sort::partition_at_index(self, index, &mut f) + } + + /// Reorder the slice with a key extraction function such that the element at `index` is at its + /// final sorted position. + /// + /// This reordering has the additional property that any value at position `i < index` will be + /// less than or equal to any value at a position `j > index` using the key extraction function. + /// Additionally, this reordering is unstable (i.e. any number of equal elements may end up at + /// position `index`), in-place (i.e. does not allocate), and `O(n)` worst-case. This function + /// is also known as "kth element" in other libraries. It returns a triplet of the following + /// values: all elements less than the one at the given index, the value at the given index, and + /// all elements greater than the one at the given index, using the provided key extraction + /// function. + /// + /// # Current implementation + /// + /// The current algorithm is based on the quickselect portion of the same quicksort algorithm + /// used for [`sort_unstable`]. + /// + /// [`sort_unstable`]: #method.sort_unstable + /// + /// # Panics + /// + /// Panics when `index >= len()`, meaning it always panics on empty slices. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_partition_at_index)] + /// + /// let mut v = [-5i32, 4, 1, -3, 2]; + /// + /// // Return the median as if the array were sorted according to absolute value. + /// v.partition_at_index_by_key(2, |a| a.abs()); + /// + /// // We are only guaranteed the slice will be one of the following, based on the way we sort + /// // about the specified index. + /// assert!(v == [1, 2, -3, 4, -5] || + /// v == [1, 2, -3, -5, 4] || + /// v == [2, 1, -3, 4, -5] || + /// v == [2, 1, -3, -5, 4]); + /// ``` + #[unstable(feature = "slice_partition_at_index", issue = "55300")] + #[inline] + pub fn partition_at_index_by_key(&mut self, index: usize, mut f: F) + -> (&mut [T], &mut T, &mut [T]) + where F: FnMut(&T) -> K, K: Ord + { + let mut g = |a: &T, b: &T| f(a).lt(&f(b)); + sort::partition_at_index(self, index, &mut g) + } + /// Moves all consecutive repeated elements to the end of the slice according to the /// [`PartialEq`] trait implementation. /// diff --git a/src/libcore/slice/sort.rs b/src/libcore/slice/sort.rs index 3f84faa049939..68f1fb4b526ad 100644 --- a/src/libcore/slice/sort.rs +++ b/src/libcore/slice/sort.rs @@ -691,3 +691,92 @@ pub fn quicksort(v: &mut [T], mut is_less: F) recurse(v, &mut is_less, None, limit); } + +fn partition_at_index_loop<'a, T, F>( mut v: &'a mut [T], mut index: usize, is_less: &mut F + , mut pred: Option<&'a T>) where F: FnMut(&T, &T) -> bool +{ + loop { + // For slices of up to this length it's probably faster to simply sort them. + const MAX_INSERTION: usize = 10; + if v.len() <= MAX_INSERTION { + insertion_sort(v, is_less); + return; + } + + // Choose a pivot + let (pivot, _) = choose_pivot(v, is_less); + + // If the chosen pivot is equal to the predecessor, then it's the smallest element in the + // slice. Partition the slice into elements equal to and elements greater than the pivot. + // This case is usually hit when the slice contains many duplicate elements. + if let Some(p) = pred { + if !is_less(p, &v[pivot]) { + let mid = partition_equal(v, pivot, is_less); + + // If we've passed our index, then we're good. + if mid > index { + return; + } + + // Otherwise, continue sorting elements greater than the pivot. + v = &mut v[mid..]; + index = index - mid; + pred = None; + continue; + } + } + + let (mid, _) = partition(v, pivot, is_less); + + // Split the slice into `left`, `pivot`, and `right`. + let (left, right) = {v}.split_at_mut(mid); + let (pivot, right) = right.split_at_mut(1); + let pivot = &pivot[0]; + + if mid < index { + v = right; + index = index - mid - 1; + pred = Some(pivot); + } else if mid > index { + v = left; + } else { + // If mid == index, then we're done, since partition() guaranteed that all elements + // after mid are greater than or equal to mid. + return; + } + } +} + +pub fn partition_at_index(v: &mut [T], index: usize, mut is_less: F) + -> (&mut [T], &mut T, &mut [T]) where F: FnMut(&T, &T) -> bool +{ + use cmp::Ordering::Less; + use cmp::Ordering::Greater; + + if index >= v.len() { + panic!("partition_at_index index {} greater than length of slice {}", index, v.len()); + } + + if mem::size_of::() == 0 { + // Sorting has no meaningful behavior on zero-sized types. Do nothing. + } else if index == v.len() - 1 { + // Find max element and place it in the last position of the array. We're free to use + // `unwrap()` here because we know v must not be empty. + let (max_index, _) = v.iter().enumerate().max_by( + |&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater }).unwrap(); + v.swap(max_index, index); + } else if index == 0 { + // Find min element and place it in the first position of the array. We're free to use + // `unwrap()` here because we know v must not be empty. + let (min_index, _) = v.iter().enumerate().min_by( + |&(_, x), &(_, y)| if is_less(x, y) { Less } else { Greater }).unwrap(); + v.swap(min_index, index); + } else { + partition_at_index_loop(v, index, &mut is_less, None); + } + + let (left, right) = v.split_at_mut(index); + let (pivot, right) = right.split_at_mut(1); + let pivot = &mut pivot[0]; + (left, pivot, right) +} diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 5e0dbb7ab2f12..392a0ffabe3d6 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -18,6 +18,7 @@ #![feature(raw)] #![feature(slice_patterns)] #![feature(sort_internals)] +#![feature(slice_partition_at_index)] #![feature(specialization)] #![feature(step_trait)] #![feature(str_internals)] diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index 4946fd52a7e12..007283b5f69c8 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -1093,6 +1093,124 @@ fn sort_unstable() { assert!(v == [0xDEADBEEF]); } +#[test] +#[cfg(not(target_arch = "wasm32"))] +#[cfg(not(miri))] // Miri does not support entropy +fn partition_at_index() { + use core::cmp::Ordering::{Equal, Greater, Less}; + use rand::rngs::SmallRng; + use rand::seq::SliceRandom; + use rand::{FromEntropy, Rng}; + + let mut rng = SmallRng::from_entropy(); + + for len in (2..21).chain(500..501) { + let mut orig = vec![0; len]; + + for &modulus in &[5, 10, 1000] { + for _ in 0..10 { + for i in 0..len { + orig[i] = rng.gen::() % modulus; + } + + let v_sorted = { + let mut v = orig.clone(); + v.sort(); + v + }; + + // Sort in default order. + for pivot in 0..len { + let mut v = orig.clone(); + v.partition_at_index(pivot); + + assert_eq!(v_sorted[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[i] <= v[j]); + } + } + } + + // Sort in ascending order. + for pivot in 0..len { + let mut v = orig.clone(); + let (left, pivot, right) = v.partition_at_index_by(pivot, |a, b| a.cmp(b)); + + assert_eq!(left.len() + right.len(), len - 1); + + for l in left { + assert!(l <= pivot); + for r in right.iter_mut() { + assert!(l <= r); + assert!(pivot <= r); + } + } + } + + // Sort in descending order. + let sort_descending_comparator = |a: &i32, b: &i32| b.cmp(a); + let v_sorted_descending = { + let mut v = orig.clone(); + v.sort_by(sort_descending_comparator); + v + }; + + for pivot in 0..len { + let mut v = orig.clone(); + v.partition_at_index_by(pivot, sort_descending_comparator); + + assert_eq!(v_sorted_descending[pivot], v[pivot]); + for i in 0..pivot { + for j in pivot..len { + assert!(v[j] <= v[i]); + } + } + } + } + } + } + + // Sort at index using a completely random comparison function. + // This will reorder the elements *somehow*, but won't panic. + let mut v = [0; 500]; + for i in 0..v.len() { + v[i] = i as i32; + } + + for pivot in 0..v.len() { + v.partition_at_index_by(pivot, |_, _| *[Less, Equal, Greater].choose(&mut rng).unwrap()); + v.sort(); + for i in 0..v.len() { + assert_eq!(v[i], i as i32); + } + } + + // Should not panic. + [(); 10].partition_at_index(0); + [(); 10].partition_at_index(5); + [(); 10].partition_at_index(9); + [(); 100].partition_at_index(0); + [(); 100].partition_at_index(50); + [(); 100].partition_at_index(99); + + let mut v = [0xDEADBEEFu64]; + v.partition_at_index(0); + assert!(v == [0xDEADBEEF]); +} + +#[test] +#[should_panic(expected = "index 0 greater than length of slice")] +fn partition_at_index_zero_length() { + [0i32; 0].partition_at_index(0); +} + +#[test] +#[should_panic(expected = "index 20 greater than length of slice")] +fn partition_at_index_past_length() { + [0i32; 10].partition_at_index(20); +} + pub mod memchr { use core::slice::memchr::{memchr, memrchr}; diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index a7ab0d6cb0408..8424c096e88c0 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -4,7 +4,7 @@ use crate::hir::def::{CtorKind, Namespace}; use crate::hir::def_id::DefId; -use crate::hir::{self, HirId, InlineAsm}; +use crate::hir::{self, HirId, InlineAsm as HirInlineAsm}; use crate::mir::interpret::{ConstValue, InterpError, Scalar}; use crate::mir::visit::MirVisitable; use rustc_apfloat::ieee::{Double, Single}; @@ -25,7 +25,7 @@ use std::slice; use std::vec::IntoIter; use std::{iter, mem, option, u32}; use syntax::ast::{self, Name}; -use syntax::symbol::InternedString; +use syntax::symbol::{InternedString, Symbol}; use syntax_pos::{Span, DUMMY_SP}; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use crate::ty::subst::{Subst, SubstsRef}; @@ -772,7 +772,7 @@ pub struct LocalDecl<'tcx> { /// e.g., via `let x: T`, then we carry that type here. The MIR /// borrow checker needs this information since it can affect /// region inference. - pub user_ty: UserTypeProjections<'tcx>, + pub user_ty: UserTypeProjections, /// Name of the local, used in debuginfo and pretty-printing. /// @@ -1735,7 +1735,7 @@ pub struct Statement<'tcx> { // `Statement` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::>() == 56); +static_assert!(MEM_SIZE_OF_STATEMENT: mem::size_of::>() == 48); impl<'tcx> Statement<'tcx> { /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -1779,12 +1779,9 @@ pub enum StatementKind<'tcx> { /// End the current live range for the storage of the local. StorageDead(Local), - /// Executes a piece of inline Assembly. - InlineAsm { - asm: Box, - outputs: Box<[Place<'tcx>]>, - inputs: Box<[(Span, Operand<'tcx>)]>, - }, + /// Executes a piece of inline Assembly. Stored in a Box to keep the size + /// of `StatementKind` low. + InlineAsm(Box>), /// Retag references in the given place, ensuring they got fresh tags. This is /// part of the Stacked Borrows model. These statements are currently only interpreted @@ -1805,7 +1802,7 @@ pub enum StatementKind<'tcx> { /// - `Contravariant` -- requires that `T_y :> T` /// - `Invariant` -- requires that `T_y == T` /// - `Bivariant` -- no effect - AscribeUserType(Place<'tcx>, ty::Variance, Box>), + AscribeUserType(Place<'tcx>, ty::Variance, Box), /// No-op. Useful for deleting instructions without affecting statement indices. Nop, @@ -1858,6 +1855,13 @@ pub enum FakeReadCause { ForLet, } +#[derive(Clone, Debug, RustcEncodable, RustcDecodable, HashStable)] +pub struct InlineAsm<'tcx> { + pub asm: HirInlineAsm, + pub outputs: Box<[Place<'tcx>]>, + pub inputs: Box<[(Span, Operand<'tcx>)]>, +} + impl<'tcx> Debug for Statement<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { use self::StatementKind::*; @@ -1880,11 +1884,8 @@ impl<'tcx> Debug for Statement<'tcx> { ref place, variant_index, } => write!(fmt, "discriminant({:?}) = {:?}", place, variant_index), - InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs), + InlineAsm(ref asm) => + write!(fmt, "asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs), AscribeUserType(ref place, ref variance, ref c_ty) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } @@ -1939,14 +1940,14 @@ impl_stable_hash_for!(struct Static<'tcx> { /// `PlaceProjection` etc below. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct Projection<'tcx, B, V, T> { +pub struct Projection { pub base: B, - pub elem: ProjectionElem<'tcx, V, T>, + pub elem: ProjectionElem, } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub enum ProjectionElem<'tcx, V, T> { +pub enum ProjectionElem { Deref, Field(Field, T), Index(V), @@ -1980,16 +1981,18 @@ pub enum ProjectionElem<'tcx, V, T> { /// "Downcast" to a variant of an ADT. Currently, we only introduce /// this for ADTs with more than one variant. It may be better to /// just introduce it always, or always for enums. - Downcast(&'tcx AdtDef, VariantIdx), + /// + /// The included Symbol is the name of the variant, used for printing MIR. + Downcast(Option, VariantIdx), } /// Alias for projections as they appear in places, where the base is a place /// and the index is a local. -pub type PlaceProjection<'tcx> = Projection<'tcx, Place<'tcx>, Local, Ty<'tcx>>; +pub type PlaceProjection<'tcx> = Projection, Local, Ty<'tcx>>; /// Alias for projections as they appear in places, where the base is a place /// and the index is a local. -pub type PlaceElem<'tcx> = ProjectionElem<'tcx, Local, Ty<'tcx>>; +pub type PlaceElem<'tcx> = ProjectionElem>; // at least on 64 bit systems, `PlaceElem` should not be larger than two pointers static_assert!(PROJECTION_ELEM_IS_2_PTRS_LARGE: @@ -1998,7 +2001,7 @@ static_assert!(PROJECTION_ELEM_IS_2_PTRS_LARGE: /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. -pub type ProjectionKind<'tcx> = ProjectionElem<'tcx, (), ()>; +pub type ProjectionKind = ProjectionElem<(), ()>; newtype_index! { pub struct Field { @@ -2019,7 +2022,9 @@ impl<'tcx> Place<'tcx> { } pub fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Place<'tcx> { - self.elem(ProjectionElem::Downcast(adt_def, variant_index)) + self.elem(ProjectionElem::Downcast( + Some(adt_def.variants[variant_index].ident.name), + variant_index)) } pub fn index(self, index: Local) -> Place<'tcx> { @@ -2080,8 +2085,11 @@ impl<'tcx> Debug for Place<'tcx> { ) }, Projection(ref data) => match data.elem { - ProjectionElem::Downcast(ref adt_def, index) => { - write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].ident) + ProjectionElem::Downcast(Some(name), _index) => { + write!(fmt, "({:?} as {})", data.base, name) + } + ProjectionElem::Downcast(None, index) => { + write!(fmt, "({:?} as variant#{:?})", data.base, index) } ProjectionElem::Deref => write!(fmt, "(*{:?})", data.base), ProjectionElem::Field(field, ty) => { @@ -2542,36 +2550,36 @@ pub struct Constant<'tcx> { /// inferred region `'1`). The second will lead to the constraint `w: /// &'static str`. #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct UserTypeProjections<'tcx> { - pub(crate) contents: Vec<(UserTypeProjection<'tcx>, Span)>, +pub struct UserTypeProjections { + pub(crate) contents: Vec<(UserTypeProjection, Span)>, } BraceStructTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections<'tcx> { + impl<'tcx> TypeFoldable<'tcx> for UserTypeProjections { contents } } -impl<'tcx> UserTypeProjections<'tcx> { +impl<'tcx> UserTypeProjections { pub fn none() -> Self { UserTypeProjections { contents: vec![] } } - pub fn from_projections(projs: impl Iterator, Span)>) -> Self { + pub fn from_projections(projs: impl Iterator) -> Self { UserTypeProjections { contents: projs.collect() } } - pub fn projections_and_spans(&self) -> impl Iterator, Span)> { + pub fn projections_and_spans(&self) -> impl Iterator { self.contents.iter() } - pub fn projections(&self) -> impl Iterator> { + pub fn projections(&self) -> impl Iterator { self.contents.iter().map(|&(ref user_type, _span)| user_type) } pub fn push_projection( mut self, - user_ty: &UserTypeProjection<'tcx>, + user_ty: &UserTypeProjection, span: Span, ) -> Self { self.contents.push((user_ty.clone(), span)); @@ -2580,7 +2588,7 @@ impl<'tcx> UserTypeProjections<'tcx> { fn map_projections( mut self, - mut f: impl FnMut(UserTypeProjection<'tcx>) -> UserTypeProjection<'tcx> + mut f: impl FnMut(UserTypeProjection) -> UserTypeProjection ) -> Self { self.contents = self.contents.drain(..).map(|(proj, span)| (f(proj), span)).collect(); self @@ -2628,14 +2636,14 @@ impl<'tcx> UserTypeProjections<'tcx> { /// `field[0]` (aka `.0`), indicating that the type of `s` is /// determined by finding the type of the `.0` field from `T`. #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, HashStable)] -pub struct UserTypeProjection<'tcx> { +pub struct UserTypeProjection { pub base: UserTypeAnnotationIndex, - pub projs: Vec>, + pub projs: Vec>, } -impl<'tcx> Copy for ProjectionKind<'tcx> { } +impl Copy for ProjectionKind { } -impl<'tcx> UserTypeProjection<'tcx> { +impl UserTypeProjection { pub(crate) fn index(mut self) -> Self { self.projs.push(ProjectionElem::Index(())); self @@ -2662,15 +2670,17 @@ impl<'tcx> UserTypeProjection<'tcx> { variant_index: VariantIdx, field: Field, ) -> Self { - self.projs.push(ProjectionElem::Downcast(adt_def, variant_index)); + self.projs.push(ProjectionElem::Downcast( + Some(adt_def.variants[variant_index].ident.name), + variant_index)); self.projs.push(ProjectionElem::Field(field, ())); self } } -CloneTypeFoldableAndLiftImpls! { ProjectionKind<'tcx>, } +CloneTypeFoldableAndLiftImpls! { ProjectionKind, } -impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for UserTypeProjection { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { use crate::mir::ProjectionElem::*; @@ -3140,13 +3150,21 @@ EnumTypeFoldableImpl! { (StatementKind::SetDiscriminant) { place, variant_index }, (StatementKind::StorageLive)(a), (StatementKind::StorageDead)(a), - (StatementKind::InlineAsm) { asm, outputs, inputs }, + (StatementKind::InlineAsm)(a), (StatementKind::Retag)(kind, place), (StatementKind::AscribeUserType)(a, v, b), (StatementKind::Nop), } } +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for InlineAsm<'tcx> { + asm, + outputs, + inputs, + } +} + EnumTypeFoldableImpl! { impl<'tcx, T> TypeFoldable<'tcx> for ClearCrossCrate { (ClearCrossCrate::Clear), @@ -3428,7 +3446,7 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { } } -impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> +impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx>, diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index ac42eacacd7bf..0eb37f0ac9e96 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -4,21 +4,17 @@ */ use crate::mir::*; -use crate::ty::subst::{Subst, SubstsRef}; -use crate::ty::{self, AdtDef, Ty, TyCtxt}; +use crate::ty::subst::Subst; +use crate::ty::{self, Ty, TyCtxt}; use crate::ty::layout::VariantIdx; use crate::hir; use crate::ty::util::IntTypeExt; #[derive(Copy, Clone, Debug)] -pub enum PlaceTy<'tcx> { - /// Normal type. - Ty { ty: Ty<'tcx> }, - - /// Downcast to a particular variant of an enum. - Downcast { adt_def: &'tcx AdtDef, - substs: SubstsRef<'tcx>, - variant_index: VariantIdx }, +pub struct PlaceTy<'tcx> { + pub ty: Ty<'tcx>, + /// Downcast to a particular variant of an enum, if included. + pub variant_index: Option, } static_assert!(PLACE_TY_IS_3_PTRS_LARGE: @@ -27,16 +23,7 @@ static_assert!(PLACE_TY_IS_3_PTRS_LARGE: impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { pub fn from_ty(ty: Ty<'tcx>) -> PlaceTy<'tcx> { - PlaceTy::Ty { ty } - } - - pub fn to_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - match *self { - PlaceTy::Ty { ty } => - ty, - PlaceTy::Downcast { adt_def, substs, variant_index: _ } => - tcx.mk_adt(adt_def, substs), - } + PlaceTy { ty, variant_index: None } } /// `place_ty.field_ty(tcx, f)` computes the type at a given field @@ -48,21 +35,20 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { /// Note that the resulting type has not been normalized. pub fn field_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, f: &Field) -> Ty<'tcx> { - // Pass `0` here so it can be used as a "default" variant_index in first arm below - let answer = match (self, VariantIdx::new(0)) { - (PlaceTy::Ty { - ty: &ty::TyS { sty: ty::TyKind::Adt(adt_def, substs), .. } }, variant_index) | - (PlaceTy::Downcast { adt_def, substs, variant_index }, _) => { - let variant_def = &adt_def.variants[variant_index]; + let answer = match self.ty.sty { + ty::TyKind::Adt(adt_def, substs) => { + let variant_def = match self.variant_index { + None => adt_def.non_enum_variant(), + Some(variant_index) => { + assert!(adt_def.is_enum()); + &adt_def.variants[variant_index] + } + }; let field_def = &variant_def.fields[f.index()]; field_def.ty(tcx, substs) } - (PlaceTy::Ty { ty }, _) => { - match ty.sty { - ty::Tuple(ref tys) => tys[f.index()], - _ => bug!("extracting field of non-tuple non-adt: {:?}", self), - } - } + ty::Tuple(ref tys) => tys[f.index()], + _ => bug!("extracting field of non-tuple non-adt: {:?}", self), }; debug!("field_ty self: {:?} f: {:?} yields: {:?}", self, f, answer); answer @@ -86,7 +72,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { pub fn projection_ty_core( self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - elem: &ProjectionElem<'tcx, V, T>, + elem: &ProjectionElem, mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>) -> PlaceTy<'tcx> where @@ -94,62 +80,43 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { { let answer = match *elem { ProjectionElem::Deref => { - let ty = self.to_ty(tcx) + let ty = self.ty .builtin_deref(true) .unwrap_or_else(|| { bug!("deref projection of non-dereferencable ty {:?}", self) }) .ty; - PlaceTy::Ty { - ty, - } + PlaceTy::from_ty(ty) } ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => - PlaceTy::Ty { - ty: self.to_ty(tcx).builtin_index().unwrap() - }, + PlaceTy::from_ty(self.ty.builtin_index().unwrap()), ProjectionElem::Subslice { from, to } => { - let ty = self.to_ty(tcx); - PlaceTy::Ty { - ty: match ty.sty { - ty::Array(inner, size) => { - let size = size.unwrap_usize(tcx); - let len = size - (from as u64) - (to as u64); - tcx.mk_array(inner, len) - } - ty::Slice(..) => ty, - _ => { - bug!("cannot subslice non-array type: `{:?}`", self) - } - } - } - } - ProjectionElem::Downcast(adt_def1, index) => - match self.to_ty(tcx).sty { - ty::Adt(adt_def, substs) => { - assert!(adt_def.is_enum()); - assert!(index.as_usize() < adt_def.variants.len()); - assert_eq!(adt_def, adt_def1); - PlaceTy::Downcast { adt_def, - substs, - variant_index: index } + PlaceTy::from_ty(match self.ty.sty { + ty::Array(inner, size) => { + let size = size.unwrap_usize(tcx); + let len = size - (from as u64) - (to as u64); + tcx.mk_array(inner, len) } + ty::Slice(..) => self.ty, _ => { - bug!("cannot downcast non-ADT type: `{:?}`", self) + bug!("cannot subslice non-array type: `{:?}`", self) } - }, + }) + } + ProjectionElem::Downcast(_name, index) => + PlaceTy { ty: self.ty, variant_index: Some(index) }, ProjectionElem::Field(ref f, ref fty) => - PlaceTy::Ty { ty: handle_field(&self, f, fty) }, + PlaceTy::from_ty(handle_field(&self, f, fty)), }; debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer); answer } } -EnumTypeFoldableImpl! { +BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for PlaceTy<'tcx> { - (PlaceTy::Ty) { ty }, - (PlaceTy::Downcast) { adt_def, substs, variant_index }, + ty, + variant_index, } } @@ -159,9 +126,9 @@ impl<'tcx> Place<'tcx> { { match *self { Place::Base(PlaceBase::Local(index)) => - PlaceTy::Ty { ty: local_decls.local_decls()[index].ty }, + PlaceTy::from_ty(local_decls.local_decls()[index].ty), Place::Base(PlaceBase::Static(ref data)) => - PlaceTy::Ty { ty: data.ty }, + PlaceTy::from_ty(data.ty), Place::Projection(ref proj) => proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem), } @@ -186,7 +153,7 @@ impl<'tcx> Place<'tcx> { match place { Place::Projection(ref proj) => match proj.elem { ProjectionElem::Field(field, _ty) => { - let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); + let base_ty = proj.base.ty(mir, *tcx).ty; if (base_ty.is_closure() || base_ty.is_generator()) && (!by_ref || mir.upvar_decls[field.index()].by_ref) @@ -218,7 +185,7 @@ impl<'tcx> Rvalue<'tcx> { tcx.mk_array(operand.ty(local_decls, tcx), count) } Rvalue::Ref(reg, bk, ref place) => { - let place_ty = place.ty(local_decls, tcx).to_ty(tcx); + let place_ty = place.ty(local_decls, tcx).ty; tcx.mk_ref(reg, ty::TypeAndMut { ty: place_ty, @@ -244,7 +211,7 @@ impl<'tcx> Rvalue<'tcx> { operand.ty(local_decls, tcx) } Rvalue::Discriminant(ref place) => { - let ty = place.ty(local_decls, tcx).to_ty(tcx); + let ty = place.ty(local_decls, tcx).ty; if let ty::Adt(adt_def, _) = ty.sty { adt_def.repr.discr_type().to_ty(tcx) } else { @@ -293,7 +260,7 @@ impl<'tcx> Operand<'tcx> { { match self { &Operand::Copy(ref l) | - &Operand::Move(ref l) => l.ty(local_decls, tcx).to_ty(tcx), + &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, &Operand::Constant(ref c) => c.ty, } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 4d44dc197cb78..b04c28cde571c 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -137,7 +137,7 @@ macro_rules! make_mir_visitor { fn visit_ascribe_user_ty(&mut self, place: & $($mutability)? Place<'tcx>, variance: & $($mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection<'tcx>, + user_ty: & $($mutability)? UserTypeProjection, location: Location) { self.super_ascribe_user_ty(place, variance, user_ty, location); } @@ -205,7 +205,7 @@ macro_rules! make_mir_visitor { fn visit_user_type_projection( &mut self, - ty: & $($mutability)? UserTypeProjection<'tcx>, + ty: & $($mutability)? UserTypeProjection, ) { self.super_user_type_projection(ty); } @@ -391,15 +391,15 @@ macro_rules! make_mir_visitor { location ); } - StatementKind::InlineAsm { outputs, inputs, asm: _ } => { - for output in & $($mutability)? outputs[..] { + StatementKind::InlineAsm(asm) => { + for output in & $($mutability)? asm.outputs[..] { self.visit_place( output, PlaceContext::MutatingUse(MutatingUseContext::AsmOutput), location ); } - for (span, input) in & $($mutability)? inputs[..] { + for (span, input) in & $($mutability)? asm.inputs[..] { self.visit_span(span); self.visit_operand(input, location); } @@ -700,7 +700,7 @@ macro_rules! make_mir_visitor { fn super_ascribe_user_ty(&mut self, place: & $($mutability)? Place<'tcx>, _variance: & $($mutability)? ty::Variance, - user_ty: & $($mutability)? UserTypeProjection<'tcx>, + user_ty: & $($mutability)? UserTypeProjection, location: Location) { self.visit_place( place, @@ -777,7 +777,7 @@ macro_rules! make_mir_visitor { min_length: _, from_end: _ } => { } - ProjectionElem::Downcast(_adt_def, _variant_index) => { + ProjectionElem::Downcast(_name, _variant_index) => { } } } @@ -851,7 +851,7 @@ macro_rules! make_mir_visitor { fn super_user_type_projection( &mut self, - _ty: & $($mutability)? UserTypeProjection<'tcx>, + _ty: & $($mutability)? UserTypeProjection, ) { } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 77330c7a9d1b2..03936a82c7151 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -125,7 +125,7 @@ pub struct CtxtInterners<'tcx> { clauses: InternedSet<'tcx, List>>, goal: InternedSet<'tcx, GoalKind<'tcx>>, goal_list: InternedSet<'tcx, List>>, - projs: InternedSet<'tcx, List>>, + projs: InternedSet<'tcx, List>, const_: InternedSet<'tcx, Const<'tcx>>, } @@ -1802,7 +1802,7 @@ nop_list_lift!{Ty<'a> => Ty<'tcx>} nop_list_lift!{ExistentialPredicate<'a> => ExistentialPredicate<'tcx>} nop_list_lift!{Predicate<'a> => Predicate<'tcx>} nop_list_lift!{CanonicalVarInfo => CanonicalVarInfo} -nop_list_lift!{ProjectionKind<'a> => ProjectionKind<'tcx>} +nop_list_lift!{ProjectionKind => ProjectionKind} // this is the impl for `&'a InternalSubsts<'a>` nop_list_lift!{Kind<'a> => Kind<'tcx>} @@ -2261,9 +2261,9 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, InternalSubsts<'t } } -impl<'tcx: 'lcx, 'lcx> Borrow<[ProjectionKind<'lcx>]> - for Interned<'tcx, List>> { - fn borrow<'a>(&'a self) -> &'a [ProjectionKind<'lcx>] { +impl<'tcx> Borrow<[ProjectionKind]> + for Interned<'tcx, List> { + fn borrow<'a>(&'a self) -> &'a [ProjectionKind] { &self.0[..] } } @@ -2391,22 +2391,22 @@ direct_interners!('tcx, ); macro_rules! slice_interners { - ($($field:ident: $method:ident($ty:ident)),+) => ( + ($($field:ident: $method:ident($ty:ty)),+) => ( $(intern_method!( 'tcx, $field: $method( - &[$ty<'tcx>], + &[$ty], |a, v| List::from_arena(a, v), Deref::deref, - |xs: &[$ty<'_>]| xs.iter().any(keep_local)) -> List<$ty<'tcx>>);)+ - ) + |xs: &[$ty]| xs.iter().any(keep_local)) -> List<$ty>);)+ + ); } slice_interners!( - existential_predicates: _intern_existential_predicates(ExistentialPredicate), - predicates: _intern_predicates(Predicate), - type_list: _intern_type_list(Ty), - substs: _intern_substs(Kind), - clauses: _intern_clauses(Clause), - goal_list: _intern_goals(Goal), + existential_predicates: _intern_existential_predicates(ExistentialPredicate<'tcx>), + predicates: _intern_predicates(Predicate<'tcx>), + type_list: _intern_type_list(Ty<'tcx>), + substs: _intern_substs(Kind<'tcx>), + clauses: _intern_clauses(Clause<'tcx>), + goal_list: _intern_goals(Goal<'tcx>), projs: _intern_projs(ProjectionKind) ); @@ -2774,7 +2774,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn intern_projs(self, ps: &[ProjectionKind<'tcx>]) -> &'tcx List> { + pub fn intern_projs(self, ps: &[ProjectionKind]) -> &'tcx List { if ps.len() == 0 { List::empty() } else { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 4f1fda3f4e534..262dc30033472 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -936,7 +936,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { } } -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { +impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); folder.tcx().intern_projs(&v) diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs index facae9a979706..8253a1672454d 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/src/librustc_codegen_ssa/mir/analyze.rs @@ -172,14 +172,14 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> // ZSTs don't require any actual memory access. let elem_ty = base_ty .projection_ty(cx.tcx(), &proj.elem) - .to_ty(cx.tcx()); + .ty; let elem_ty = self.fx.monomorphize(&elem_ty); if cx.layout_of(elem_ty).is_zst() { return; } if let mir::ProjectionElem::Field(..) = proj.elem { - let layout = cx.layout_of(base_ty.to_ty(cx.tcx())); + let layout = cx.layout_of(base_ty.ty); if cx.is_backend_immediate(layout) || cx.is_backend_scalar_pair(layout) { // Recurse with the same context, instead of `Projection`, // potentially stopping at non-operand projections, @@ -247,7 +247,7 @@ impl<'mir, 'a: 'mir, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> PlaceContext::MutatingUse(MutatingUseContext::Drop) => { let ty = mir::Place::Base(mir::PlaceBase::Local(local)).ty(self.fx.mir, self.fx.cx.tcx()); - let ty = self.fx.monomorphize(&ty.to_ty(self.fx.cx.tcx())); + let ty = self.fx.monomorphize(&ty.ty); // Only need the place if we're actually dropping it. if self.fx.cx.type_needs_drop(ty) { diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 53e8f7ed88b4e..65f7e023fa226 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -301,7 +301,7 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { target: mir::BasicBlock, unwind: Option, ) { - let ty = location.ty(self.mir, bx.tcx()).to_ty(bx.tcx()); + let ty = location.ty(self.mir, bx.tcx()).ty; let ty = self.monomorphize(&ty); let drop_fn = monomorphize::resolve_drop_in_place(bx.tcx(), ty); diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 9ed7e26729f53..2b7b900475332 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -494,8 +494,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::ProjectionElem::Subslice { from, to } => { let mut subslice = cg_base.project_index(bx, bx.cx().const_usize(from as u64)); - let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty } - .projection_ty(tcx, &projection.elem).to_ty(tcx); + let projected_ty = PlaceTy::from_ty(cg_base.layout.ty) + .projection_ty(tcx, &projection.elem).ty; subslice.layout = bx.cx().layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { @@ -523,6 +523,6 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn monomorphized_place_ty(&self, place: &mir::Place<'tcx>) -> Ty<'tcx> { let tcx = self.cx.tcx(); let place_ty = place.ty(self.mir, tcx); - self.monomorphize(&place_ty.to_ty(tcx)) + self.monomorphize(&place_ty.ty) } } diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/src/librustc_codegen_ssa/mir/statement.rs index 97729e8aeb35f..618d05245d2ca 100644 --- a/src/librustc_codegen_ssa/mir/statement.rs +++ b/src/librustc_codegen_ssa/mir/statement.rs @@ -68,13 +68,13 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } bx } - mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { - let outputs = outputs.iter().map(|output| { + mir::StatementKind::InlineAsm(ref asm) => { + let outputs = asm.outputs.iter().map(|output| { self.codegen_place(&mut bx, output) }).collect(); - let input_vals = inputs.iter() - .fold(Vec::with_capacity(inputs.len()), |mut acc, (span, input)| { + let input_vals = asm.inputs.iter() + .fold(Vec::with_capacity(asm.inputs.len()), |mut acc, (span, input)| { let op = self.codegen_operand(&mut bx, input); if let OperandValue::Immediate(_) = op.val { acc.push(op.immediate()); @@ -85,8 +85,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { acc }); - if input_vals.len() == inputs.len() { - let res = bx.codegen_inline_asm(asm, outputs, input_vals); + if input_vals.len() == asm.inputs.len() { + let res = bx.codegen_inline_asm(&asm.asm, outputs, input_vals); if !res { span_err!(bx.sess(), statement.source_info.span, E0668, "malformed inline assembly"); diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs index a94350f9cde00..c04a36fe9c69c 100644 --- a/src/librustc_mir/borrow_check/error_reporting.rs +++ b/src/librustc_mir/borrow_check/error_reporting.rs @@ -13,6 +13,7 @@ use rustc::mir::{ Static, StaticKind, TerminatorKind, VarBindingForm, }; use rustc::ty::{self, DefIdTree}; +use rustc::ty::layout::VariantIdx; use rustc::ty::print::Print; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; @@ -201,7 +202,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { ); } - let ty = used_place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = used_place.ty(self.mir, self.infcx.tcx).ty; let needs_note = match ty.sty { ty::Closure(id, _) => { let tables = self.infcx.tcx.typeck_tables_of(id); @@ -216,7 +217,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { let mpi = self.move_data.moves[move_out_indices[0]].path; let place = &self.move_data.move_paths[mpi].place; - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = place.ty(self.mir, self.infcx.tcx).ty; let opt_name = self.describe_place_with_options(place, IncludingDowncast(true)); let note_msg = match opt_name { Some(ref name) => format!("`{}`", name), @@ -596,8 +597,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Define a small closure that we can use to check if the type of a place // is a union. let is_union = |place: &Place<'tcx>| -> bool { - place.ty(self.mir, self.infcx.tcx) - .to_ty(self.infcx.tcx) + place.ty(self.mir, self.infcx.tcx).ty .ty_adt_def() .map(|adt| adt.is_union()) .unwrap_or(false) @@ -646,7 +646,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // Also compute the name of the union type, eg. `Foo` so we // can add a helpful note with it. - let ty = base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = base.ty(self.mir, self.infcx.tcx).ty; return Some((desc_base, desc_first, desc_second, ty.to_string())); }, @@ -1761,20 +1761,22 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// End-user visible description of the `field`nth field of `base` - fn describe_field(&self, base: &Place<'_>, field: Field) -> String { + fn describe_field(&self, base: &Place<'tcx>, field: Field) -> String { match *base { Place::Base(PlaceBase::Local(local)) => { let local = &self.mir.local_decls[local]; - self.describe_field_from_ty(&local.ty, field) + self.describe_field_from_ty(&local.ty, field, None) } Place::Base(PlaceBase::Static(ref static_)) => - self.describe_field_from_ty(&static_.ty, field), + self.describe_field_from_ty(&static_.ty, field, None), Place::Projection(ref proj) => match proj.elem { ProjectionElem::Deref => self.describe_field(&proj.base, field), - ProjectionElem::Downcast(def, variant_index) => - def.variants[variant_index].fields[field.index()].ident.to_string(), + ProjectionElem::Downcast(_, variant_index) => { + let base_ty = base.ty(self.mir, self.infcx.tcx).ty; + self.describe_field_from_ty(&base_ty, field, Some(variant_index)) + } ProjectionElem::Field(_, field_type) => { - self.describe_field_from_ty(&field_type, field) + self.describe_field_from_ty(&field_type, field, None) } ProjectionElem::Index(..) | ProjectionElem::ConstantIndex { .. } @@ -1786,24 +1788,34 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { } /// End-user visible description of the `field_index`nth field of `ty` - fn describe_field_from_ty(&self, ty: &ty::Ty<'_>, field: Field) -> String { + fn describe_field_from_ty( + &self, + ty: &ty::Ty<'_>, + field: Field, + variant_index: Option + ) -> String { if ty.is_box() { // If the type is a box, the field is described from the boxed type - self.describe_field_from_ty(&ty.boxed_ty(), field) + self.describe_field_from_ty(&ty.boxed_ty(), field, variant_index) } else { match ty.sty { - ty::Adt(def, _) => if def.is_enum() { - field.index().to_string() - } else { - def.non_enum_variant().fields[field.index()] + ty::Adt(def, _) => { + let variant = if let Some(idx) = variant_index { + assert!(def.is_enum()); + &def.variants[idx] + } else { + def.non_enum_variant() + }; + variant.fields[field.index()] .ident .to_string() }, ty::Tuple(_) => field.index().to_string(), ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { - self.describe_field_from_ty(&ty, field) + self.describe_field_from_ty(&ty, field, variant_index) } - ty::Array(ty, _) | ty::Slice(ty) => self.describe_field_from_ty(&ty, field), + ty::Array(ty, _) | ty::Slice(ty) => + self.describe_field_from_ty(&ty, field, variant_index), ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { // Convert the def-id into a node-id. node-ids are only valid for // the local code in the current crate, so this returns an `Option` in case @@ -1861,7 +1873,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { StorageDeadOrDrop::LocalStorageDead | StorageDeadOrDrop::BoxedStorageDead => { assert!( - base.ty(self.mir, tcx).to_ty(tcx).is_box(), + base.ty(self.mir, tcx).ty.is_box(), "Drop of value behind a reference or raw pointer" ); StorageDeadOrDrop::BoxedStorageDead @@ -1869,7 +1881,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { StorageDeadOrDrop::Destructor(_) => base_access, }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { - let base_ty = base.ty(self.mir, tcx).to_ty(tcx); + let base_ty = base.ty(self.mir, tcx).ty; match base_ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 820a990c633e0..a8c151a22eebc 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -525,16 +525,12 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx flow_state, ); } - StatementKind::InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => { + StatementKind::InlineAsm(ref asm) => { let context = ContextKind::InlineAsm.new(location); - for (o, output) in asm.outputs.iter().zip(outputs.iter()) { + for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should - // be encoeded through MIR place derefs instead. + // be encoded through MIR place derefs instead. self.access_place( context, (output, o.span), @@ -558,7 +554,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx ); } } - for (_, input) in inputs.iter() { + for (_, input) in asm.inputs.iter() { self.consume_operand(context, (input, span), flow_state); } } @@ -616,8 +612,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx let drop_place_ty = drop_place.ty(self.mir, self.infcx.tcx); // Erase the regions. - let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty) - .to_ty(self.infcx.tcx); + let drop_place_ty = self.infcx.tcx.erase_regions(&drop_place_ty).ty; // "Lift" into the gcx -- once regions are erased, this type should be in the // global arenas; this "lift" operation basically just asserts that is true, but @@ -1641,7 +1636,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // assigning to `P.f` requires `P` itself // be already initialized let tcx = self.infcx.tcx; - match base.ty(self.mir, tcx).to_ty(tcx).sty { + match base.ty(self.mir, tcx).ty.sty { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( context, InitializationRequiringAction::Assignment, @@ -1746,7 +1741,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).to_ty(tcx).sty { + if let ty::TyKind::Adt(def, _) = base.ty(this.mir, tcx).ty.sty { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { this.move_data.moves[*moi].source.is_predecessor_of( @@ -2007,7 +2002,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> { Place::Projection(ref proj) => { match proj.elem { ProjectionElem::Deref => { - let base_ty = proj.base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let base_ty = proj.base.ty(self.mir, self.infcx.tcx).ty; // Check the kind of deref to decide match base_ty.sty { diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index bd4bf67d0b154..b6e7996586e4a 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -266,7 +266,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // Inspect the type of the content behind the // borrow to provide feedback about why this // was a move rather than a copy. - let ty = place.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = place.ty(self.mir, self.infcx.tcx).ty; let is_upvar_field_projection = self.prefixes(&original_path, PrefixSet::All) .any(|p| p.is_upvar_field_projection(self.mir, &self.infcx.tcx) @@ -530,7 +530,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { // We're only interested in assignments (in particular, where the // assignment came from - was it an `Rc` or `Arc`?). if let StatementKind::Assign(_, box Rvalue::Ref(_, _, source)) = &stmt.kind { - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = source.ty(self.mir, self.infcx.tcx).ty; let ty = match ty.sty { ty::TyKind::Ref(_, ty, _) => ty, _ => ty, @@ -555,7 +555,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { _ => continue, }; - let ty = source.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx); + let ty = source.ty(self.mir, self.infcx.tcx).ty; let ty = match ty.sty { ty::TyKind::Ref(_, ty, _) => ty, _ => ty, @@ -581,7 +581,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { base, elem: ProjectionElem::Deref, }) = place { - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_unsafe_ptr() { + if base.ty(self.mir, self.infcx.tcx).ty.is_unsafe_ptr() { return BorrowedContentSource::DerefRawPointer; } } diff --git a/src/librustc_mir/borrow_check/mutability_errors.rs b/src/librustc_mir/borrow_check/mutability_errors.rs index f351212e9d587..8a55a59b15b17 100644 --- a/src/librustc_mir/borrow_check/mutability_errors.rs +++ b/src/librustc_mir/borrow_check/mutability_errors.rs @@ -64,7 +64,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Field(upvar_index, _), }) => { debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + base.ty(self.mir, self.infcx.tcx).ty )); item_msg = format!("`{}`", access_place_desc.unwrap()); @@ -85,7 +85,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { item_msg = format!("`{}`", access_place_desc.unwrap()); debug_assert!(self.mir.local_decls[Local::new(1)].ty.is_region_ptr()); debug_assert!(is_closure_or_generator( - the_place_err.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + the_place_err.ty(self.mir, self.infcx.tcx).ty )); reason = if access_place.is_upvar_field_projection(self.mir, @@ -110,7 +110,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { reason = ", as it is immutable for the pattern guard".to_string(); } else { let pointer_type = - if base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx).is_region_ptr() { + if base.ty(self.mir, self.infcx.tcx).ty.is_region_ptr() { "`&` reference" } else { "`*const` pointer" @@ -232,7 +232,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { if let Some((span, message)) = annotate_struct_field( self.infcx.tcx, - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx), + base.ty(self.mir, self.infcx.tcx).ty, field, ) { err.span_suggestion( @@ -304,7 +304,7 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { elem: ProjectionElem::Field(upvar_index, _), }) => { debug_assert!(is_closure_or_generator( - base.ty(self.mir, self.infcx.tcx).to_ty(self.infcx.tcx) + base.ty(self.mir, self.infcx.tcx).ty )); err.span_label(span, format!("cannot {ACT}", ACT = act)); diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 375dd6e97f1a2..bf9cff1e4ae03 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -174,7 +174,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx &mut self, _place: &Place<'tcx>, _variance: &ty::Variance, - _user_ty: &UserTypeProjection<'tcx>, + _user_ty: &UserTypeProjection, _location: Location, ) { } diff --git a/src/librustc_mir/borrow_check/nll/invalidation.rs b/src/librustc_mir/borrow_check/nll/invalidation.rs index 9f51fb9e969c3..8217200b05788 100644 --- a/src/librustc_mir/borrow_check/nll/invalidation.rs +++ b/src/librustc_mir/borrow_check/nll/invalidation.rs @@ -92,16 +92,12 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { JustWrite, ); } - StatementKind::InlineAsm { - ref asm, - ref outputs, - ref inputs, - } => { + StatementKind::InlineAsm(ref asm) => { let context = ContextKind::InlineAsm.new(location); - for (o, output) in asm.outputs.iter().zip(outputs.iter()) { + for (o, output) in asm.asm.outputs.iter().zip(asm.outputs.iter()) { if o.is_indirect { // FIXME(eddyb) indirect inline asm outputs should - // be encoeded through MIR place derefs instead. + // be encoded through MIR place derefs instead. self.access_place( context, output, @@ -117,7 +113,7 @@ impl<'cx, 'tcx, 'gcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx, 'gcx> { ); } } - for (_, input) in inputs.iter() { + for (_, input) in asm.inputs.iter() { self.consume_operand(context, input); } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 5041a7ffee258..b06ebbdbf34f6 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -450,9 +450,8 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_place: {:?}", place); let place_ty = match place { - Place::Base(PlaceBase::Local(index)) => PlaceTy::Ty { - ty: self.mir.local_decls[*index].ty, - }, + Place::Base(PlaceBase::Local(index)) => + PlaceTy::from_ty(self.mir.local_decls[*index].ty), Place::Base(PlaceBase::Static(box Static { kind, ty: sty })) => { let sty = self.sanitize_type(place, sty); let check_err = @@ -493,7 +492,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { check_err(self, place, ty, sty); } } - PlaceTy::Ty { ty: sty } + PlaceTy::from_ty(sty) } Place::Projection(ref proj) => { let base_context = if context.is_mutating_use() { @@ -502,12 +501,10 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) }; let base_ty = self.sanitize_place(&proj.base, location, base_context); - if let PlaceTy::Ty { ty } = base_ty { - if ty.references_error() { + if base_ty.variant_index.is_none() { + if base_ty.ty.references_error() { assert!(self.errors_reported); - return PlaceTy::Ty { - ty: self.tcx().types.err, - }; + return PlaceTy::from_ty(self.tcx().types.err); } } self.sanitize_projection(base_ty, &proj.elem, place, location) @@ -517,7 +514,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let tcx = self.tcx(); let trait_ref = ty::TraitRef { def_id: tcx.lang_items().copy_trait().unwrap(), - substs: tcx.mk_substs_trait(place_ty.to_ty(tcx), &[]), + substs: tcx.mk_substs_trait(place_ty.ty, &[]), }; // In order to have a Copy operand, the type T of the @@ -615,40 +612,40 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ) -> PlaceTy<'tcx> { debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place); let tcx = self.tcx(); - let base_ty = base.to_ty(tcx); + let base_ty = base.ty; match *pi { ProjectionElem::Deref => { let deref_ty = base_ty.builtin_deref(true); - PlaceTy::Ty { - ty: deref_ty.map(|t| t.ty).unwrap_or_else(|| { + PlaceTy::from_ty( + deref_ty.map(|t| t.ty).unwrap_or_else(|| { span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty) - }), - } + }) + ) } ProjectionElem::Index(i) => { - let index_ty = Place::Base(PlaceBase::Local(i)).ty(self.mir, tcx).to_ty(tcx); + let index_ty = Place::Base(PlaceBase::Local(i)).ty(self.mir, tcx).ty; if index_ty != tcx.types.usize { - PlaceTy::Ty { - ty: span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), - } + PlaceTy::from_ty( + span_mirbug_and_err!(self, i, "index by non-usize {:?}", i), + ) } else { - PlaceTy::Ty { - ty: base_ty.builtin_index().unwrap_or_else(|| { + PlaceTy::from_ty( + base_ty.builtin_index().unwrap_or_else(|| { span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) }), - } + ) } } ProjectionElem::ConstantIndex { .. } => { // consider verifying in-bounds - PlaceTy::Ty { - ty: base_ty.builtin_index().unwrap_or_else(|| { + PlaceTy::from_ty( + base_ty.builtin_index().unwrap_or_else(|| { span_mirbug_and_err!(self, place, "index of non-array {:?}", base_ty) }), - } + ) } - ProjectionElem::Subslice { from, to } => PlaceTy::Ty { - ty: match base_ty.sty { + ProjectionElem::Subslice { from, to } => PlaceTy::from_ty( + match base_ty.sty { ty::Array(inner, size) => { let size = size.unwrap_usize(tcx); let min_size = (from as u64) + (to as u64); @@ -666,35 +663,39 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { ty::Slice(..) => base_ty, _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), }, - }, - ProjectionElem::Downcast(adt_def1, index) => match base_ty.sty { - ty::Adt(adt_def, substs) if adt_def.is_enum() && adt_def == adt_def1 => { + ), + ProjectionElem::Downcast(maybe_name, index) => match base_ty.sty { + ty::Adt(adt_def, _substs) if adt_def.is_enum() => { if index.as_usize() >= adt_def.variants.len() { - PlaceTy::Ty { - ty: span_mirbug_and_err!( + PlaceTy::from_ty( + span_mirbug_and_err!( self, place, "cast to variant #{:?} but enum only has {:?}", index, adt_def.variants.len() ), - } + ) } else { - PlaceTy::Downcast { - adt_def, - substs, - variant_index: index, + PlaceTy { + ty: base_ty, + variant_index: Some(index), } } } - _ => PlaceTy::Ty { - ty: span_mirbug_and_err!( - self, - place, - "can't downcast {:?} as {:?}", - base_ty, - adt_def1 - ), + _ => { + let ty = if let Some(name) = maybe_name { + span_mirbug_and_err!( + self, + place, + "can't downcast {:?} as {:?}", + base_ty, + name + ) + } else { + span_mirbug_and_err!(self, place, "can't downcast {:?}", base_ty) + }; + PlaceTy::from_ty(ty) }, }, ProjectionElem::Field(field, fty) => { @@ -723,7 +724,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { field_count ), } - PlaceTy::Ty { ty: fty } + PlaceTy::from_ty(fty) } } } @@ -743,12 +744,13 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> { let tcx = self.tcx(); let (variant, substs) = match base_ty { - PlaceTy::Downcast { - adt_def, - substs, - variant_index, - } => (&adt_def.variants[variant_index], substs), - PlaceTy::Ty { ty } => match ty.sty { + PlaceTy { ty, variant_index: Some(variant_index) } => { + match ty.sty { + ty::TyKind::Adt(adt_def, substs) => (&adt_def.variants[variant_index], substs), + _ => bug!("can't have downcast of non-adt type"), + } + } + PlaceTy { ty, variant_index: None } => match ty.sty { ty::Adt(adt_def, substs) if !adt_def.is_enum() => (&adt_def.variants[VariantIdx::new(0)], substs), ty::Closure(def_id, substs) => { @@ -1161,7 +1163,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { &mut self, a: Ty<'tcx>, v: ty::Variance, - user_ty: &UserTypeProjection<'tcx>, + user_ty: &UserTypeProjection, locations: Locations, category: ConstraintCategory, ) -> Fallible<()> { @@ -1185,7 +1187,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}", user_ty.base, annotated_type, user_ty.projs, curr_projected_ty); - let ty = curr_projected_ty.to_ty(tcx); + let ty = curr_projected_ty.ty; self.relate_types(a, v, ty, locations, category)?; Ok(()) @@ -1333,7 +1335,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { _ => ConstraintCategory::Assignment, }; - let place_ty = place.ty(mir, tcx).to_ty(tcx); + let place_ty = place.ty(mir, tcx).ty; let rv_ty = rv.ty(mir, tcx); if let Err(terr) = self.sub_types_or_anon(rv_ty, place_ty, location.to_locations(), category) @@ -1385,7 +1387,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { ref place, variant_index, } => { - let place_type = place.ty(mir, tcx).to_ty(tcx); + let place_type = place.ty(mir, tcx).ty; let adt = match place_type.sty { TyKind::Adt(adt, _) if adt.is_enum() => adt, _ => { @@ -1407,7 +1409,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { }; } StatementKind::AscribeUserType(ref place, variance, box ref projection) => { - let place_ty = place.ty(mir, tcx).to_ty(tcx); + let place_ty = place.ty(mir, tcx).ty; if let Err(terr) = self.relate_type_and_user_type( place_ty, variance, @@ -1463,7 +1465,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { target: _, unwind: _, } => { - let place_ty = location.ty(mir, tcx).to_ty(tcx); + let place_ty = location.ty(mir, tcx).ty; let rv_ty = value.ty(mir, tcx); let locations = term_location.to_locations(); @@ -1611,7 +1613,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { let tcx = self.tcx(); match *destination { Some((ref dest, _target_block)) => { - let dest_ty = dest.ty(mir, tcx).to_ty(tcx); + let dest_ty = dest.ty(mir, tcx).ty; let category = match *dest { Place::Base(PlaceBase::Local(RETURN_PLACE)) => { if let Some(BorrowCheckContext { @@ -2370,7 +2372,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> { match *elem { ProjectionElem::Deref => { let tcx = self.infcx.tcx; - let base_ty = base.ty(mir, tcx).to_ty(tcx); + let base_ty = base.ty(mir, tcx).ty; debug!("add_reborrow_constraint - base_ty = {:?}", base_ty); match base_ty.sty { diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/src/librustc_mir/borrow_check/place_ext.rs index 6bc56ab721f98..8269b7b95f490 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/src/librustc_mir/borrow_check/place_ext.rs @@ -63,7 +63,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { tcx, mir, locals_state_at_exit), ProjectionElem::Deref => { - let ty = proj.base.ty(mir, tcx).to_ty(tcx); + let ty = proj.base.ty(mir, tcx).ty; match ty.sty { // For both derefs of raw pointers and `&T` // references, the original path is `Copy` and diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/src/librustc_mir/borrow_check/places_conflict.rs index 52119d6b19bc0..fbe8b8485dda5 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/src/librustc_mir/borrow_check/places_conflict.rs @@ -191,7 +191,7 @@ fn place_components_conflict<'gcx, 'tcx>( Place::Projection(box Projection { base, elem }) => (base, elem), _ => bug!("place has no base?"), }; - let base_ty = base.ty(mir, tcx).to_ty(tcx); + let base_ty = base.ty(mir, tcx).ty; match (elem, &base_ty.sty, access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) @@ -427,7 +427,7 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>( debug!("place_element_conflict: DISJOINT-OR-EQ-FIELD"); Overlap::EqualOrDisjoint } else { - let ty = pi1.base.ty(mir, tcx).to_ty(tcx); + let ty = pi1.base.ty(mir, tcx).ty; match ty.sty { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index e70c9e81ebd16..866f1cf994e69 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -139,7 +139,7 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> { // derefs, except we stop at the deref of a shared // reference. - let ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let ty = proj.base.ty(self.mir, self.tcx).ty; match ty.sty { ty::RawPtr(_) | ty::Ref( diff --git a/src/librustc_mir/build/block.rs b/src/librustc_mir/build/block.rs index cba5039122a76..7469aceee3a9e 100644 --- a/src/librustc_mir/build/block.rs +++ b/src/librustc_mir/build/block.rs @@ -163,7 +163,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // Then, the block may have an optional trailing expression which is a “return” value // of the block, which is stored into `destination`. let tcx = this.hir.tcx(); - let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx); + let destination_ty = destination.ty(&this.local_decls, tcx).ty; if let Some(expr) = expr { let tail_result_is_ignored = destination_ty.is_unit() || this.block_context.currently_ignores_tail_results(); diff --git a/src/librustc_mir/build/expr/stmt.rs b/src/librustc_mir/build/expr/stmt.rs index 9527a23279570..b58914b017fd4 100644 --- a/src/librustc_mir/build/expr/stmt.rs +++ b/src/librustc_mir/build/expr/stmt.rs @@ -188,11 +188,11 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { block, Statement { source_info, - kind: StatementKind::InlineAsm { - asm: box asm.clone(), + kind: StatementKind::InlineAsm(box InlineAsm { + asm: asm.clone(), outputs, inputs, - }, + }), }, ); this.block_context.pop(); diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index be3d730c61a1d..566f1790f8f7f 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -374,7 +374,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let ty_source_info = self.source_info(user_ty_span); let user_ty = box pat_ascription_ty.user_ty( &mut self.canonical_user_type_annotations, - place.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + place.ty(&self.local_decls, self.hir.tcx()).ty, ty_source_info.span, ); self.cfg.push( @@ -575,7 +575,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub(super) fn visit_bindings( &mut self, pattern: &Pattern<'tcx>, - pattern_user_ty: UserTypeProjections<'tcx>, + pattern_user_ty: UserTypeProjections, f: &mut impl FnMut( &mut Self, Mutability, @@ -584,7 +584,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { HirId, Span, Ty<'tcx>, - UserTypeProjections<'tcx>, + UserTypeProjections, ), ) { debug!("visit_bindings: pattern={:?} pattern_user_ty={:?}", pattern, pattern_user_ty); @@ -1293,7 +1293,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { debug!("add_fake_borrows all_fake_borrows = {:?}", all_fake_borrows); all_fake_borrows.into_iter().map(|matched_place| { - let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).to_ty(tcx); + let fake_borrow_deref_ty = matched_place.ty(&self.local_decls, tcx).ty; let fake_borrow_ty = tcx.mk_imm_ref(tcx.types.re_erased, fake_borrow_deref_ty); let fake_borrow_temp = self.local_decls.push( LocalDecl::new_temp(fake_borrow_ty, temp_span) @@ -1587,7 +1587,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { let user_ty = box ascription.user_ty.clone().user_ty( &mut self.canonical_user_type_annotations, - ascription.source.ty(&self.local_decls, self.hir.tcx()).to_ty(self.hir.tcx()), + ascription.source.ty(&self.local_decls, self.hir.tcx()).ty, source_info.span ); self.cfg.push( @@ -1701,7 +1701,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { mode: BindingMode, var_id: HirId, var_ty: Ty<'tcx>, - user_ty: UserTypeProjections<'tcx>, + user_ty: UserTypeProjections, has_guard: ArmHasGuard, opt_match_place: Option<(Option>, Span)>, pat_span: Span, diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 0c93984fda806..b06022196106a 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -693,7 +693,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { // So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`, // we want to create a set of derived match-patterns like // `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`. - let elem = ProjectionElem::Downcast(adt_def, variant_index); + let elem = ProjectionElem::Downcast( + Some(adt_def.variants[variant_index].ident.name), variant_index); let downcast_place = match_pair.place.elem(elem); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter() diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index d76d3765ac710..d71a13dec5a2f 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -70,7 +70,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { pub fn consume_by_copy_or_move(&self, place: Place<'tcx>) -> Operand<'tcx> { let tcx = self.hir.tcx(); - let ty = place.ty(&self.local_decls, tcx).to_ty(tcx); + let ty = place.ty(&self.local_decls, tcx).ty; if !self.hir.type_is_copy_modulo_regions(ty, DUMMY_SP) { Operand::Move(place) } else { diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index f78c82a93020c..aae4590a387a7 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -49,7 +49,7 @@ pub fn move_path_children_matching<'tcx, F>(move_data: &MoveData<'tcx>, fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, mir: &Mir<'tcx>, place: &mir::Place<'tcx>) -> bool { - let ty = place.ty(mir, tcx).to_ty(tcx); + let ty = place.ty(mir, tcx).ty; match ty.sty { ty::Array(..) => { debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", @@ -141,7 +141,7 @@ pub(crate) fn on_all_drop_children_bits<'a, 'gcx, 'tcx, F>( { on_all_children_bits(tcx, mir, &ctxt.move_data, path, |child| { let place = &ctxt.move_data.move_paths[path].place; - let ty = place.ty(mir, tcx).to_ty(tcx); + let ty = place.ty(mir, tcx).ty; debug!("on_all_drop_children_bits({:?}, {:?} : {:?})", path, place, ty); let gcx = tcx.global_tcx(); diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/src/librustc_mir/dataflow/impls/borrows.rs index b47aff3a4f855..5a3105ed16049 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/src/librustc_mir/dataflow/impls/borrows.rs @@ -288,8 +288,8 @@ impl<'a, 'gcx, 'tcx> BitDenotation<'tcx> for Borrows<'a, 'gcx, 'tcx> { self.kill_borrows_on_place(sets, &Place::Base(PlaceBase::Local(local))); } - mir::StatementKind::InlineAsm { ref outputs, ref asm, .. } => { - for (output, kind) in outputs.iter().zip(&asm.outputs) { + mir::StatementKind::InlineAsm(ref asm) => { + for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { if !kind.is_indirect && !kind.is_rw { self.kill_borrows_on_place(sets, output); } diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/src/librustc_mir/dataflow/move_paths/abs_domain.rs index 6dcc0325ec1ac..b26547c4ff77e 100644 --- a/src/librustc_mir/dataflow/move_paths/abs_domain.rs +++ b/src/librustc_mir/dataflow/move_paths/abs_domain.rs @@ -18,8 +18,7 @@ use rustc::ty::Ty; pub struct AbstractOperand; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct AbstractType; -pub type AbstractElem<'tcx> = - ProjectionElem<'tcx, AbstractOperand, AbstractType>; +pub type AbstractElem = ProjectionElem; pub trait Lift { type Abstract; @@ -38,7 +37,7 @@ impl<'tcx> Lift for Ty<'tcx> { fn lift(&self) -> Self::Abstract { AbstractType } } impl<'tcx> Lift for PlaceElem<'tcx> { - type Abstract = AbstractElem<'tcx>; + type Abstract = AbstractElem; fn lift(&self) -> Self::Abstract { match *self { ProjectionElem::Deref => @@ -56,7 +55,7 @@ impl<'tcx> Lift for PlaceElem<'tcx> { from_end, }, ProjectionElem::Downcast(a, u) => - ProjectionElem::Downcast(a.clone(), u.clone()), + ProjectionElem::Downcast(a, u.clone()), } } } diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/src/librustc_mir/dataflow/move_paths/builder.rs index 71805fd02b857..011dc54f3b315 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/src/librustc_mir/dataflow/move_paths/builder.rs @@ -120,7 +120,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { let base = self.move_path_for(&proj.base)?; let mir = self.builder.mir; let tcx = self.builder.tcx; - let place_ty = proj.base.ty(mir, tcx).to_ty(tcx); + let place_ty = proj.base.ty(mir, tcx).ty; match place_ty.sty { ty::Ref(..) | ty::RawPtr(..) => return Err(MoveError::cannot_move_out_of( @@ -272,13 +272,13 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { StatementKind::FakeRead(_, ref place) => { self.create_move_path(place); } - StatementKind::InlineAsm { ref outputs, ref inputs, ref asm } => { - for (output, kind) in outputs.iter().zip(&asm.outputs) { + StatementKind::InlineAsm(ref asm) => { + for (output, kind) in asm.outputs.iter().zip(&asm.asm.outputs) { if !kind.is_indirect { self.gather_init(output, InitKind::Deep); } } - for (_, input) in inputs.iter() { + for (_, input) in asm.inputs.iter() { self.gather_operand(input); } } @@ -424,7 +424,7 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> { Place::Projection(box Projection { base, elem: ProjectionElem::Field(_, _), - }) if match base.ty(self.builder.mir, self.builder.tcx).to_ty(self.builder.tcx).sty { + }) if match base.ty(self.builder.mir, self.builder.tcx).ty.sty { ty::TyKind::Adt(def, _) if def.is_union() => true, _ => false, } => base, diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/src/librustc_mir/dataflow/move_paths/mod.rs index 7eef68e5f8073..5806a01c687cb 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/src/librustc_mir/dataflow/move_paths/mod.rs @@ -148,7 +148,7 @@ pub struct MoveData<'tcx> { /// particular path being moved.) pub loc_map: LocationMap>, pub path_map: IndexVec>, - pub rev_lookup: MovePathLookup<'tcx>, + pub rev_lookup: MovePathLookup, pub inits: IndexVec, /// Each Location `l` is mapped to the Inits that are effects /// of executing the code at `l`. @@ -258,7 +258,7 @@ impl Init { /// Tables mapping from a place to its MovePathIndex. #[derive(Debug)] -pub struct MovePathLookup<'tcx> { +pub struct MovePathLookup { locals: IndexVec, /// projections are made from a base-place and a projection @@ -267,7 +267,7 @@ pub struct MovePathLookup<'tcx> { /// subsequent search so that it is solely relative to that /// base-place). For the remaining lookup, we map the projection /// elem to the associated MovePathIndex. - projections: FxHashMap<(MovePathIndex, AbstractElem<'tcx>), MovePathIndex> + projections: FxHashMap<(MovePathIndex, AbstractElem), MovePathIndex> } mod builder; @@ -278,7 +278,7 @@ pub enum LookupResult { Parent(Option) } -impl<'tcx> MovePathLookup<'tcx> { +impl MovePathLookup { // Unlike the builder `fn move_path_for` below, this lookup // alternative will *not* create a MovePath on the fly for an // unknown place, but will rather return the nearest available diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 622cf00ed86e7..fc12443c0923a 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -74,7 +74,7 @@ impl<'tcx> PatternTypeProjection<'tcx> { annotations: &mut CanonicalUserTypeAnnotations<'tcx>, inferred_ty: Ty<'tcx>, span: Span, - ) -> UserTypeProjection<'tcx> { + ) -> UserTypeProjection { UserTypeProjection { base: annotations.push(CanonicalUserTypeAnnotation { span, @@ -1094,7 +1094,7 @@ CloneImpls!{ <'tcx> Span, Field, Mutability, ast::Name, hir::HirId, usize, ty::Const<'tcx>, Region<'tcx>, Ty<'tcx>, BindingMode, &'tcx AdtDef, SubstsRef<'tcx>, &'tcx Kind<'tcx>, UserType<'tcx>, - UserTypeProjection<'tcx>, PatternTypeProjection<'tcx> + UserTypeProjection, PatternTypeProjection<'tcx> } impl<'tcx> PatternFoldable<'tcx> for FieldPattern<'tcx> { diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 4d51772d5ea14..4f7b59a5a9a95 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -558,7 +558,7 @@ where pub fn place_projection( &mut self, base: PlaceTy<'tcx, M::PointerTag>, - proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>, + proj_elem: &mir::ProjectionElem>, ) -> EvalResult<'tcx, PlaceTy<'tcx, M::PointerTag>> { use rustc::mir::ProjectionElem::*; Ok(match *proj_elem { diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 45b346b641362..af875c2f9e8a1 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -625,8 +625,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { } mir::TerminatorKind::Drop { ref location, .. } | mir::TerminatorKind::DropAndReplace { ref location, .. } => { - let ty = location.ty(self.mir, self.tcx) - .to_ty(self.tcx); + let ty = location.ty(self.mir, self.tcx).ty; let ty = tcx.subst_and_normalize_erasing_regions( self.param_substs, ty::ParamEnv::reveal_all(), diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/src/librustc_mir/transform/add_moves_for_packed_drops.rs index e8528eee0bcab..b6436ec70eef2 100644 --- a/src/librustc_mir/transform/add_moves_for_packed_drops.rs +++ b/src/librustc_mir/transform/add_moves_for_packed_drops.rs @@ -106,7 +106,7 @@ fn add_move_for_packed_drop<'a, 'tcx>( }; let source_info = terminator.source_info; - let ty = location.ty(mir, tcx).to_ty(tcx); + let ty = location.ty(mir, tcx).ty; let temp = patch.new_temp(ty, terminator.source_info.span); let storage_dead_block = patch.new_block(BasicBlockData { diff --git a/src/librustc_mir/transform/add_retag.rs b/src/librustc_mir/transform/add_retag.rs index b13a5fd2fd1c0..9b9e6594296ba 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/src/librustc_mir/transform/add_retag.rs @@ -87,7 +87,7 @@ impl MirPass for AddRetag { let needs_retag = |place: &Place<'tcx>| { // FIXME: Instead of giving up for unstable places, we should introduce // a temporary and retag on that. - is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).to_ty(tcx), tcx) + is_stable(place) && may_have_reference(place.ty(&*local_decls, tcx).ty, tcx) }; // PART 1 diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 0e31515e4af90..93f3afe1aea6b 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -227,7 +227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } let is_borrow_of_interior_mut = context.is_borrow() && !base .ty(self.mir, self.tcx) - .to_ty(self.tcx) + .ty .is_freeze(self.tcx, self.param_env, self.source_info.span); // prevent // * `&mut x.field` @@ -249,7 +249,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { self.source_info = self.mir.local_decls[local].source_info; } } - let base_ty = base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = base.ty(self.mir, self.tcx).ty; match base_ty.sty { ty::RawPtr(..) => { self.require_unsafe("dereference of raw pointer", @@ -420,7 +420,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { }) = place { match *elem { ProjectionElem::Field(..) => { - let ty = base.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); + let ty = base.ty(&self.mir.local_decls, self.tcx).ty; match ty.sty { ty::Adt(def, _) => match self.tcx.layout_scalar_valid_range(def.did) { (Bound::Unbounded, Bound::Unbounded) => {}, diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 0d43602d89986..e0ff71cbe52f8 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -556,7 +556,7 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> { if let StatementKind::Assign(ref place, ref rval) = statement.kind { let place_ty: ty::Ty<'tcx> = place .ty(&self.mir.local_decls, self.tcx) - .to_ty(self.tcx); + .ty; if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) { if let Some(value) = self.const_prop(rval, place_layout, statement.source_info) { if let Place::Base(PlaceBase::Local(local)) = *place { diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index 1063381d6aa57..027ae70b06a17 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -319,8 +319,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { work_list.push(target); // If the location doesn't actually need dropping, treat it like // a regular goto. - let ty = location.ty(callee_mir, tcx).subst(tcx, callsite.substs); - let ty = ty.to_ty(tcx); + let ty = location.ty(callee_mir, tcx).subst(tcx, callsite.substs).ty; if ty.needs_drop(tcx, param_env) { cost += CALL_PENALTY; if let Some(unwind) = unwind { @@ -563,7 +562,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> { assert!(args.next().is_none()); let tuple = Place::Base(PlaceBase::Local(tuple)); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_mir, tcx).to_ty(tcx).sty { + let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_mir, tcx).ty.sty { s } else { bug!("Closure arguments are not passed as a tuple"); diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index e0e64fd1f9b54..7e925f65ee2d7 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -82,14 +82,14 @@ impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue { if let ProjectionElem::Deref = projection.elem { - if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { + if projection.base.ty(self.mir, self.tcx).ty.is_region_ptr() { self.optimizations.and_stars.insert(location); } } } if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(&self.mir.local_decls, self.tcx).to_ty(self.tcx); + let place_ty = place.ty(&self.mir.local_decls, self.tcx).ty; if let TyKind::Array(_, len) = place_ty.sty { let span = self.mir.source_info(location).span; let ty = self.tcx.types.usize; diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs index 54fc63f30571e..dda9457cc8ccf 100644 --- a/src/librustc_mir/transform/lower_128bit.rs +++ b/src/librustc_mir/transform/lower_128bit.rs @@ -135,7 +135,7 @@ fn check_lang_item_type<'a, 'tcx, D>( let sig = poly_sig.no_bound_vars().unwrap(); let lhs_ty = lhs.ty(local_decls, tcx); let rhs_ty = rhs.ty(local_decls, tcx); - let place_ty = place.ty(local_decls, tcx).to_ty(tcx); + let place_ty = place.ty(local_decls, tcx).ty; let expected = [lhs_ty, rhs_ty, place_ty]; assert_eq!(sig.inputs_and_output[..], expected, "lang item `{}`", tcx.def_path_str(did)); diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index 73b88e9904bf2..43723aaf568da 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -310,7 +310,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> { place = &mut proj.base; }; - let ty = place.ty(local_decls, self.tcx).to_ty(self.tcx); + let ty = place.ty(local_decls, self.tcx).ty; let span = statement.source_info.span; Operand::Move(mem::replace(place, promoted_place(ty, span))) diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index e533066e6b9e2..5adcbf84da5a0 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -168,7 +168,7 @@ trait Qualif { cx, proj.base.ty(cx.mir, cx.tcx) .projection_ty(cx.tcx, &proj.elem) - .to_ty(cx.tcx), + .ty, ); match proj.elem { ProjectionElem::Deref | @@ -245,7 +245,7 @@ trait Qualif { // Special-case reborrows to be more like a copy of the reference. if let Place::Projection(ref proj) = *place { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let base_ty = proj.base.ty(cx.mir, cx.tcx).ty; if let ty::Ref(..) = base_ty.sty { return Self::in_place(cx, &proj.base); } @@ -301,7 +301,7 @@ impl Qualif for HasMutInterior { // allowed in constants (and the `Checker` will error), and/or it // won't be promoted, due to `&mut ...` or interior mutability. Rvalue::Ref(_, kind, ref place) => { - let ty = place.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let ty = place.ty(cx.mir, cx.tcx).ty; if let BorrowKind::Mut { .. } = kind { // In theory, any zero-sized value could be borrowed @@ -398,7 +398,7 @@ impl Qualif for IsNotConst { ProjectionElem::Field(..) => { if cx.mode == Mode::Fn { - let base_ty = proj.base.ty(cx.mir, cx.tcx).to_ty(cx.tcx); + let base_ty = proj.base.ty(cx.mir, cx.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { if def.is_union() { return true; @@ -988,7 +988,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // `not_const` errors out in const contexts self.not_const() } - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.mir, self.tcx).ty; match self.mode { Mode::Fn => {}, _ => { @@ -1012,7 +1012,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { ProjectionElem::Subslice {..} | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.mir, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { if def.is_union() { match self.mode { @@ -1069,7 +1069,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { let mut is_reborrow = false; if let Place::Projection(ref proj) = *place { if let ProjectionElem::Deref = proj.elem { - let base_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let base_ty = proj.base.ty(self.mir, self.tcx).ty; if let ty::Ref(..) = base_ty.sty { is_reborrow = true; } @@ -1193,7 +1193,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { self.assign(dest, ValueSource::Call { callee: func, args, - return_ty: dest.ty(self.mir, self.tcx).to_ty(self.tcx), + return_ty: dest.ty(self.mir, self.tcx).ty, }, location); } @@ -1367,7 +1367,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { if let Some(span) = needs_drop { // Double-check the type being dropped, to minimize false positives. - let ty = place.ty(self.mir, self.tcx).to_ty(self.tcx); + let ty = place.ty(self.mir, self.tcx).ty; if ty.needs_drop(self.tcx, self.param_env) { struct_span_err!(self.tcx.sess, span, E0493, "destructors cannot be evaluated at compile-time") diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index b1d898bb5b026..616944dd7ef99 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -69,7 +69,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> { from_end: false} = proj.elem { // no need to transformation } else { - let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx); + let place_ty = proj.base.ty(self.mir, self.tcx).ty; if let ty::Array(item_ty, const_size) = place_ty.sty { if let Some(size) = const_size.assert_usize(self.tcx) { assert!(size <= u32::max_value() as u64, @@ -195,7 +195,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut { let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2); let opt_size = opt_src_place.and_then(|src_place| { - let src_ty = src_place.ty(mir, tcx).to_ty(tcx); + let src_ty = src_place.ty(mir, tcx).ty; if let ty::Array(_, ref size_o) = src_ty.sty { size_o.assert_usize(tcx) } else { diff --git a/src/librustc_mir/util/alignment.rs b/src/librustc_mir/util/alignment.rs index 7be34d001df07..788b7fdaaf912 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/src/librustc_mir/util/alignment.rs @@ -17,7 +17,7 @@ pub fn is_disaligned<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return false } - let ty = place.ty(local_decls, tcx).to_ty(tcx); + let ty = place.ty(local_decls, tcx).ty; match tcx.layout_raw(param_env.and(ty)) { Ok(layout) if layout.align.abi.bytes() == 1 => { // if the alignment is 1, the type can't be further @@ -46,7 +46,7 @@ fn is_within_packed<'a, 'tcx, L>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // encountered a Deref, which is ABI-aligned ProjectionElem::Deref => break, ProjectionElem::Field(..) => { - let ty = base.ty(local_decls, tcx).to_ty(tcx); + let ty = base.ty(local_decls, tcx).ty; match ty.sty { ty::Adt(def, _) if def.repr.packed() => { return true diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index 37b38338ab9a7..2d275c9a13792 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -122,7 +122,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> where D: DropElaborator<'b, 'tcx> { fn place_ty(&self, place: &Place<'tcx>) -> Ty<'tcx> { - place.ty(self.elaborator.mir(), self.tcx()).to_ty(self.tcx()) + place.ty(self.elaborator.mir(), self.tcx()).ty } fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> { @@ -412,8 +412,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> self.path, variant_index); if let Some(variant_path) = subpath { let base_place = self.place.clone().elem( - ProjectionElem::Downcast(adt, variant_index) - ); + ProjectionElem::Downcast(Some(adt.variants[variant_index].ident.name), + variant_index)); let fields = self.move_paths_for_fields( &base_place, variant_path,