Change:
cc
I think you have a PR that improves type inference in some cases where closures are involved (?), do you know if by chance that fixes this as well?
This is not closure specific:
This must be duo to . It seems to enforce the numeric fallback rule a bit too eagerly.
Another example from IRC is that type checked while didn't. Rather interesting.
edwardw, not just that, type inference regressed slightly at the time of the range stabilization PR.
also related
Have a partial fix by deferring numeric fallback, but it seems to hit now.
OK, so I spent some time digging into this. I don't think that deferring numeric fallback is necessarily the solution. sorry if I kept disappearing on IRC, I had to put my head down and study the log to see what was happening. So what seems to happen is that we correctly come up with the constraint: However, we are unable to make the connection between and . The reason is that the new has separate impls for each of the numeric types, whereas the old had only impl for a type . When we process the projections, we first try to resolve (without considering the output type ), and we get ambiguity, because there are many impls that could apply. Unfortunately this all seems a bit right to me. Basically we're trying to infer the type of the range from the output type, which is the reverse direction inference is supposed to go. When we used a blanket impl, we were able to resolve this because there was only one impl for . Probably the best fix is to go back to that, actually, but this is an interesting quandry. I'll have to think about it a bit.
To be clear, the example I was digging into was
Also, to put it another way: having a single blanket impl allows us to draw the connection that when you iterate over , you get . With the current setup of many distinct impls, that is not known to be true.
After some discussion with on RFC, I just wanted to clarify a few things (I myself was a touch confused too). the impl is probably the easiest way to fix this in the short term. , to some extent, this limitation is an artifact of how trait matching is implemented. That is, we intentionally do not take output bindings into account when selecting traits. However, it doesn't have to be this way, but it'd take some work to massage the trait matching infrastructure, since impl selection doesn't presently have access to output binding information, that'd have to be propagated inward. It might be interesting to try and address this in a more wholistic way (i.e., something that accounts for the full set of facts that are registered). particular, the important constraint that we MUST maintain is that, during trans, given the input types, we can derive the output type. But it's permissible for us to use the output type to derive the input type during type checking, since once inference is done, we then have the input types to supply during trans so that we can rederive the output.
The fix is very simple then. Thanks for helping diagnose the problem and pointing to the right direction.

Discussion:
} } <del> macro_rules! range_impl { </del> <ins> macro_rules! range_exact_iter_impl { </ins> ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] <del> impl Iterator for ::ops::Range<$t> { type Item = $t; </del> <ins> impl ExactSizeIterator for ::ops::Range<$t> { </ins> #[inline] <del> 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>) { </del> <ins> fn len(&self) -> usize { </ins> debug_assert!(self.end >= self.start); <del> let hint = (self.end - self.start) as usize; (hint, Some(hint)) </del> <ins> (self.end - self.start) as usize </ins> } } <del> #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for ::ops::Range<$t> {} </del> )*) } <del> 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); } </del> <ins> #[stable(feature = "rust1", since = "1.0.0")] impl<A: Int> Iterator for ::ops::Range<A> { type Item = A; </ins> <del> return None; } </del> <ins> #[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 </ins> } <del> )*) } 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); } </del> <ins> } </ins> <del> return None; } } </del> <ins> #[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) } } </ins> <del> #[stable(feature = "rust1", since = "1.0.0")] impl Iterator for ::ops::RangeFrom<$t> { type Item = $t; </del> <ins> range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32); #[cfg(target_pointer_width = "64")] range_exact_iter_impl!(u64 i64); </ins> <del> #[inline] fn next(&mut self) -> Option<$t> { let result = self.start; self.start += 1; debug_assert!(result < self.start); return Some(result); } </del> <ins> #[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 </ins> } <del> )*) </del> <ins> } </ins> } <del> 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); </del> <ins> #[stable(feature = "rust1", since = "1.0.0")] impl<A: Int> Iterator for ::ops::RangeFrom<A> { type Item = A; </ins> <del> range_other_impls!(usize u8 u16 u32 u64 isize i8 i16 i32 i64); </del> <ins> #[inline] fn next(&mut self) -> Option<A> { let result = self.start; self.start = self.start + Int::one(); debug_assert!(result < self.start); Some(result) } } </ins> /// An iterator that repeats an element endlessly #[derive(Clone)]

// Float => does not implement iterator. for i in 0f32..42f32 {} <del> //~^ ERROR `core::iter::Iterator` is not implemented for the type `core::ops::Range<f32>` //~^^ ERROR //~^^^ ERROR // FIXME(#21528) not fulfilled obligation error should be reported once, not thrice </del> <ins> //~^ ERROR the trait `core::num::Int` is not implemented for the type `f32` </ins> // Unsized type. let arr: &[_] = &[1us, 2, 3];

<ins> // 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]; } } </ins>