Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Type inference failure after switching to unboxed closure #19499

Closed
japaric opened this issue Dec 3, 2014 · 1 comment
Closed

Type inference failure after switching to unboxed closure #19499

japaric opened this issue Dec 3, 2014 · 1 comment
Labels
A-closures Area: closures (`|args| { .. }`) A-typesystem Area: The type system

Comments

@japaric
Copy link
Member

japaric commented Dec 3, 2014

STR

#![feature(unboxed_closures)]

trait IteratorExt2<A> {
    fn inspect2<F>(self, f: F) -> Inspect<A, Self, F> where F: FnMut(&A);
}

struct Inspect<A, I, F> where I: Iterator<A>, F: FnMut(&A) {
    iter: I,
    f: F,
}

fn main() {
    let xs = [1u, 2, 3, 4];
    // Trigger
    let mut n = 0;  // Err
    //let mut n = 0u;  // Ok

    let ys = xs.iter()
               .map(|&x| x)
               .inspect2(|_| n += 1)
                //~^ error: unable to infer enough type information about `closure`; type annotations required
               //.inspect2(|&mut: _| n += 1)  // This doesn't work either (same error as above)
               .collect::<Vec<uint>>();

    // NOTE: This constrains `n` to be `uint`
    assert_eq!(n, xs.len());
    assert_eq!(xs[], ys[]);
}

impl<A, I> IteratorExt2<A> for I where I: Iterator<A> {
    fn inspect2<F>(self, f: F) -> Inspect<A, I, F> where F: FnMut(&A) {
        Inspect {
            iter: self,
            f: f,
        }
    }
}

impl<A, I, F> Inspect<A, I, F> where I: Iterator<A>, F: FnMut(&A) {
    #[inline]
    fn do_inspect(&mut self, elt: Option<A>) -> Option<A> {
        match elt {
            Some(ref a) => (self.f)(a),
            None => ()
        }

        elt
    }
}

impl<A, I, F> Iterator<A> for Inspect<A, I, F> where I: Iterator<A>, F: FnMut(&A) {
    fn next(&mut self) -> Option<A> {
        let next = self.iter.next();
        self.do_inspect(next)
    }

    fn size_hint(&self) -> (uint, Option<uint>) {
        self.iter.size_hint()
    }
}

Version

#19449 on top of 21ba1d5

The code under main is actually a test (see test_inspect in libcoretest/iter.rs) that was passing with the boxed version of Inspect, but after moving Inspect to unboxed closures (as seen above) compiling that test now errors due to a type inference failure.

To fix the compilation n had to be type annotated: let mut n = 0u, however this shouldn't be necessary because assert_eq!(n, xs.len()) should already force n to be uint.

TL;DR This should compile because it has enough type information, but for some reason it doesn't.

cc @nikomatsakis

@eddyb
Copy link
Member

eddyb commented Dec 3, 2014

It's calling .collect() that triggers the error, it goes away if you provide a hint for n after calling inspect but before collect (or any other iterator method).
AFAICT method resolution shouldn't be able to tell apart unboxed closures so I don't understand why it would be trying to resolve the type of its captures.

My version of main:

fn main() {
    let n = 0;
    let it = Some(1u).into_iter().inspect2(|_| {n;});
    //~^ error: unable to infer enough type information about `Inspect<uint, core::option::Item<uint>, closure>`; type annotations required

    // Trigger
    // let _: uint = n;  // Ok
    it.count();
    let _: uint = n;  // Err
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: closures (`|args| { .. }`) A-typesystem Area: The type system
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants