]> git.lizzy.rs Git - rust.git/commitdiff
Make sure type inference with `a..b` as good as `range(a,b)`
authorEdward Wang <edward.yu.wang@gmail.com>
Sat, 31 Jan 2015 14:19:13 +0000 (22:19 +0800)
committerEdward Wang <edward.yu.wang@gmail.com>
Sun, 1 Feb 2015 06:08:14 +0000 (14:08 +0800)
The new `::ops::Range` has separated implementations for each of the
numeric types, while the old `::iter::Range` has one for type `Int`.
However, we do not take output bindings into account when selecting
traits. So it confuses `typeck` and makes the new range does not work as
good as the old one when it comes to type inference.

This patch implements `Iterator` for the new range for one type `Int`.
This limitation could be lifted, however, if we ever reconsider the
output types' role in type inference.

Closes #21595
Closes #21649
Closes #21672

src/libcore/iter.rs
src/test/run-pass/range-type-infer.rs [new file with mode: 0644]

index b0906651da803abfa24e682c9eecbcd2f1967b1b..0a9dc23f18d1aa57cdf2f9d4d11852d1705a75be 100644 (file)
@@ -2796,93 +2796,71 @@ fn next(&mut self) -> Option<A> {
     }
 }
 
-macro_rules! range_impl {
+macro_rules! range_exact_iter_impl {
     ($($t:ty)*) => ($(
         #[stable(feature = "rust1", since = "1.0.0")]
-        impl Iterator for ::ops::Range<$t> {
-            type Item = $t;
-
+        impl ExactSizeIterator for ::ops::Range<$t> {
             #[inline]
-            fn next(&mut self) -> Option<$t> {
-                if self.start < self.end {
-                    let result = self.start;
-                    self.start += 1;
-                    return Some(result);
-                }
-
-                return None;
-            }
-
-            #[inline]
-            fn size_hint(&self) -> (usize, Option<usize>) {
+            fn len(&self) -> usize {
                 debug_assert!(self.end >= self.start);
-                let hint = (self.end - self.start) as usize;
-                (hint, Some(hint))
+                (self.end - self.start) as usize
             }
         }
-
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl ExactSizeIterator for ::ops::Range<$t> {}
     )*)
 }
 
-macro_rules! range_impl_no_hint {
-    ($($t:ty)*) => ($(
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl Iterator for ::ops::Range<$t> {
-            type Item = $t;
-
-            #[inline]
-            fn next(&mut self) -> Option<$t> {
-                if self.start < self.end {
-                    let result = self.start;
-                    self.start += 1;
-                    return Some(result);
-                }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Int> Iterator for ::ops::Range<A> {
+    type Item = A;
 
-                return None;
-            }
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        if self.start < self.end {
+            let result = self.start;
+            self.start = self.start + Int::one();
+            Some(result)
+        } else {
+            None
         }
-    )*)
-}
-
-macro_rules! range_other_impls {
-    ($($t:ty)*) => ($(
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl DoubleEndedIterator for ::ops::Range<$t> {
-            #[inline]
-            fn next_back(&mut self) -> Option<$t> {
-                if self.start < self.end {
-                    self.end -= 1;
-                    return Some(self.end);
-                }
+    }
 
-                return None;
-            }
-        }
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        debug_assert!(self.end >= self.start);
+        let hint = (self.end - self.start).to_uint();
+        (hint.unwrap_or(0), hint)
+    }
+}
 
-        #[stable(feature = "rust1", since = "1.0.0")]
-        impl Iterator for ::ops::RangeFrom<$t> {
-            type Item = $t;
+range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
+#[cfg(target_pointer_width = "64")]
+range_exact_iter_impl!(u64 i64);
 
-            #[inline]
-            fn next(&mut self) -> Option<$t> {
-                let result = self.start;
-                self.start += 1;
-                debug_assert!(result < self.start);
-                return Some(result);
-            }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Int> DoubleEndedIterator for ::ops::Range<A> {
+    #[inline]
+    fn next_back(&mut self) -> Option<A> {
+        if self.start < self.end {
+            self.end = self.end - Int::one();
+            Some(self.end)
+        } else {
+            None
         }
-    )*)
+    }
 }
 
-range_impl!(usize u8 u16 u32 isize i8 i16 i32);
-#[cfg(target_pointer_width = "64")]
-range_impl!(u64 i64);
-#[cfg(target_pointer_width = "32")]
-range_impl_no_hint!(u64 i64);
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<A: Int> Iterator for ::ops::RangeFrom<A> {
+    type Item = A;
 
-range_other_impls!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
+    #[inline]
+    fn next(&mut self) -> Option<A> {
+        let result = self.start;
+        self.start = self.start + Int::one();
+        debug_assert!(result < self.start);
+        Some(result)
+    }
+}
 
 /// An iterator that repeats an element endlessly
 #[derive(Clone)]
diff --git a/src/test/run-pass/range-type-infer.rs b/src/test/run-pass/range-type-infer.rs
new file mode 100644 (file)
index 0000000..51945a4
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Make sure the type inference for the new range expression work as
+// good as the old one. Check out issue #21672, #21595 and #21649 for
+// more details.
+
+fn main() {
+    let xs = (0..8).map(|i| i == 1u64).collect::<Vec<_>>();
+    assert_eq!(xs[1], true);
+    let xs = (0..8).map(|i| 1u64 == i).collect::<Vec<_>>();
+    assert_eq!(xs[1], true);
+    let xs: Vec<u8> = (0..10).collect();
+    assert_eq!(xs.len(), 10);
+
+    for x in 0..10 { x % 2; }
+    for x in 0..100 { x as f32; }
+
+    let array = [true, false];
+    for i in 0..1 { array[i]; }
+}