Skip to content

Commit

Permalink
Use more associated types in core::iter.
Browse files Browse the repository at this point in the history
This concretely improves type inference of some cases (see included
test). I assume the compiler struggles to reason about multiple layers
of generic type parameters (even with associated-type equalities) but
*can* understand pure associated types, since they are always directly
computable from the input types.
  • Loading branch information
huonw committed Mar 5, 2015
1 parent fed1249 commit 7bcf7fb
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 46 deletions.
94 changes: 48 additions & 46 deletions src/libcore/iter.rs
Expand Up @@ -1279,14 +1279,14 @@ pub struct Cloned<I> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, D, I> Iterator for Cloned<I> where
T: Clone,
D: Deref<Target=T>,
I: Iterator<Item=D>,
impl<I> Iterator for Cloned<I> where
I: Iterator,
I::Item: Deref,
<I::Item as Deref>::Target: Clone
{
type Item = T;
type Item = <I::Item as Deref>::Target;

fn next(&mut self) -> Option<T> {
fn next(&mut self) -> Option<<Self as Iterator>::Item> {
self.it.next().cloned()
}

Expand All @@ -1296,36 +1296,36 @@ impl<T, D, I> Iterator for Cloned<I> where
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, D, I> DoubleEndedIterator for Cloned<I> where
T: Clone,
D: Deref<Target=T>,
I: DoubleEndedIterator<Item=D>,
impl<I> DoubleEndedIterator for Cloned<I> where
I: DoubleEndedIterator,
I::Item: Deref,
<I::Item as Deref>::Target: Clone
{
fn next_back(&mut self) -> Option<T> {
fn next_back(&mut self) -> Option<<Self as Iterator>::Item> {
self.it.next_back().cloned()
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, D, I> ExactSizeIterator for Cloned<I> where
T: Clone,
D: Deref<Target=T>,
I: ExactSizeIterator<Item=D>,
impl<I> ExactSizeIterator for Cloned<I> where
I: ExactSizeIterator,
I::Item: Deref,
<I::Item as Deref>::Target: Clone
{}

#[unstable(feature = "core", reason = "trait is experimental")]
impl<T, D, I> RandomAccessIterator for Cloned<I> where
T: Clone,
D: Deref<Target=T>,
I: RandomAccessIterator<Item=D>
impl<I> RandomAccessIterator for Cloned<I> where
I: RandomAccessIterator,
I::Item: Deref,
<I::Item as Deref>::Target: Clone
{
#[inline]
fn indexable(&self) -> usize {
self.it.indexable()
}

#[inline]
fn idx(&mut self, index: usize) -> Option<T> {
fn idx(&mut self, index: usize) -> Option<<Self as Iterator>::Item> {
self.it.idx(index).cloned()
}
}
Expand Down Expand Up @@ -1400,11 +1400,14 @@ pub struct Chain<A, B> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A, B> Iterator for Chain<A, B> where A: Iterator<Item=T>, B: Iterator<Item=T> {
type Item = T;
impl<A, B> Iterator for Chain<A, B> where
A: Iterator,
B: Iterator<Item = A::Item>
{
type Item = A::Item;

#[inline]
fn next(&mut self) -> Option<T> {
fn next(&mut self) -> Option<A::Item> {
if self.flag {
self.b.next()
} else {
Expand Down Expand Up @@ -1434,12 +1437,12 @@ impl<T, A, B> Iterator for Chain<A, B> where A: Iterator<Item=T>, B: Iterator<It
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, A, B> DoubleEndedIterator for Chain<A, B> where
A: DoubleEndedIterator<Item=T>,
B: DoubleEndedIterator<Item=T>,
impl<A, B> DoubleEndedIterator for Chain<A, B> where
A: DoubleEndedIterator,
B: DoubleEndedIterator<Item=A::Item>,
{
#[inline]
fn next_back(&mut self) -> Option<T> {
fn next_back(&mut self) -> Option<A::Item> {
match self.b.next_back() {
Some(x) => Some(x),
None => self.a.next_back()
Expand All @@ -1448,9 +1451,9 @@ impl<T, A, B> DoubleEndedIterator for Chain<A, B> where
}

#[unstable(feature = "core", reason = "trait is experimental")]
impl<T, A, B> RandomAccessIterator for Chain<A, B> where
A: RandomAccessIterator<Item=T>,
B: RandomAccessIterator<Item=T>,
impl<A, B> RandomAccessIterator for Chain<A, B> where
A: RandomAccessIterator,
B: RandomAccessIterator<Item = A::Item>,
{
#[inline]
fn indexable(&self) -> usize {
Expand All @@ -1459,7 +1462,7 @@ impl<T, A, B> RandomAccessIterator for Chain<A, B> where
}

#[inline]
fn idx(&mut self, index: usize) -> Option<T> {
fn idx(&mut self, index: usize) -> Option<A::Item> {
let len = self.a.indexable();
if index < len {
self.a.idx(index)
Expand All @@ -1479,14 +1482,12 @@ pub struct Zip<A, B> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, A, B> Iterator for Zip<A, B> where
A: Iterator<Item = T>,
B: Iterator<Item = U>,
impl<A, B> Iterator for Zip<A, B> where A: Iterator, B: Iterator
{
type Item = (T, U);
type Item = (A::Item, B::Item);

#[inline]
fn next(&mut self) -> Option<(T, U)> {
fn next(&mut self) -> Option<(A::Item, B::Item)> {
match self.a.next() {
None => None,
Some(x) => match self.b.next() {
Expand Down Expand Up @@ -1515,12 +1516,12 @@ impl<T, U, A, B> Iterator for Zip<A, B> where
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T, U, A, B> DoubleEndedIterator for Zip<A, B> where
A: DoubleEndedIterator + ExactSizeIterator<Item=T>,
B: DoubleEndedIterator + ExactSizeIterator<Item=U>,
impl<A, B> DoubleEndedIterator for Zip<A, B> where
A: DoubleEndedIterator + ExactSizeIterator,
B: DoubleEndedIterator + ExactSizeIterator,
{
#[inline]
fn next_back(&mut self) -> Option<(T, U)> {
fn next_back(&mut self) -> Option<(A::Item, B::Item)> {
let a_sz = self.a.len();
let b_sz = self.b.len();
if a_sz != b_sz {
Expand All @@ -1540,17 +1541,17 @@ impl<T, U, A, B> DoubleEndedIterator for Zip<A, B> where
}

#[unstable(feature = "core", reason = "trait is experimental")]
impl<T, U, A, B> RandomAccessIterator for Zip<A, B> where
A: RandomAccessIterator<Item=T>,
B: RandomAccessIterator<Item=U>,
impl<A, B> RandomAccessIterator for Zip<A, B> where
A: RandomAccessIterator,
B: RandomAccessIterator
{
#[inline]
fn indexable(&self) -> usize {
cmp::min(self.a.indexable(), self.b.indexable())
}

#[inline]
fn idx(&mut self, index: usize) -> Option<(T, U)> {
fn idx(&mut self, index: usize) -> Option<(A::Item, B::Item)> {
match self.a.idx(index) {
None => None,
Some(x) => match self.b.idx(index) {
Expand Down Expand Up @@ -2071,8 +2072,9 @@ pub struct Scan<I, St, F> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<A, B, I: Iterator<Item=A>, St, F> Iterator for Scan<I, St, F> where
F: FnMut(&mut St, A) -> Option<B>,
impl<B, I, St, F> Iterator for Scan<I, St, F> where
I: Iterator,
F: FnMut(&mut St, I::Item) -> Option<B>,
{
type Item = B;

Expand Down
25 changes: 25 additions & 0 deletions src/test/run-pass/iter-cloned-type-inference.rs
@@ -0,0 +1,25 @@
// 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.

// Test to see that the element type of .cloned() can be inferred
// properly. Previously this would fail to deduce the type of `sum`.

#![feature(core)]

use std::iter::AdditiveIterator;

fn square_sum(v: &[i64]) -> i64 {
let sum = v.iter().cloned().sum();
sum * sum
}

fn main() {
assert_eq!(36, square_sum(&[1,2,3]));
}

0 comments on commit 7bcf7fb

Please sign in to comment.