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

Box<Iterator> (and &mut Iterator) does not implement Iterator #20953

Closed
BurntSushi opened this issue Jan 11, 2015 · 9 comments · Fixed by #21392
Closed

Box<Iterator> (and &mut Iterator) does not implement Iterator #20953

BurntSushi opened this issue Jan 11, 2015 · 9 comments · Fixed by #21392
Labels
A-trait-system Area: Trait system

Comments

@BurntSushi
Copy link
Member

This code fails to compile:

fn main() {
    let mut shrinker = Box::new(vec![1].into_iter()) as Box<Iterator<Item=i32>>;
    println!("{:?}", shrinker.next());
    for v in shrinker { println!("{:?}", v); }
}

error message:

[andrew@Liger play] rustc scratch2.rs 
scratch2.rs:32:14: 32:22 error: `for` loop expression has type `Box<core::iter::Iterator>` which does not implement the `Iterator` trait; maybe try .iter()
scratch2.rs:32     for v in shrinker { println!("{:?}", v); }
                            ^~~~~~~~
error: aborting due to previous error

A similar error occurs if &mut Iterator is used instead of Box<Iterator>. However, if you comment out the for loop, the call to next works just fine. I thought maybe it had something to do with auto-deref, so I tried dereferencing the iterator:

for v in *shrinker { println!("{:?}", v); }

but rustc dumps core:

[andrew@Liger play] rustc scratch2.rs 
rustc: /home/rustbuild/src/rust-buildbot/slave/nightly-dist-rustc-linux/build/src/llvm/lib/IR/Instructions.cpp:1086: void llvm::StoreInst::AssertOK(): Assertion `getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"' failed.
Aborted (core dumped)

I'm not sure, but this may be related to #20605? rustc dumps core when I try &mut Iterator too.

rustc version:

[andrew@Liger play] rustc --version
rustc 1.0.0-nightly (44a287e6e 2015-01-08 17:03:40 -0800)
@Gankra
Copy link
Contributor

Gankra commented Jan 11, 2015

CC @nikomatsakis

@chris-morgan
Copy link
Member

I think the problem is worse than this; trait objects in general don’t seem to be being recognised as implementing their traits:

trait Trait { }

fn a(x: &Trait) { try(x); }
fn b(x: &mut Trait) { try(x); }
fn c(x: Box<Trait>) { try(x); }
fn try<T: Trait>(t: T) { }

fn main() { }

All three fail:

i.rs:3:19: 3:22 error: the trait `Trait` is not implemented for the type `&Trait`
i.rs:3 fn a(x: &Trait) { try(x); }
                         ^~~
i.rs:4:23: 4:26 error: the trait `Trait` is not implemented for the type `&mut Trait`
i.rs:4 fn b(x: &mut Trait) { try(x); }
                             ^~~
i.rs:5:23: 5:26 error: the trait `Trait` is not implemented for the type `Box<Trait>`
i.rs:5 fn c(x: Box<Trait>) { try(x); }
                             ^~~
error: aborting due to 3 previous errors

@eddyb
Copy link
Member

eddyb commented Jan 12, 2015

I'm not sure this is a bug at all. You're pretty much asking for an automatic impl<T> Trait for &mut T where T: Trait - I did come up with a Deref & DerefMut-based model that would kinda work for this and IIRC @nikomatsakis pointed out that object-safe traits would eventually qualify for this. We do have object safety now, so it might be doable, but I wouldn't bet on it making into 1.0.
In the meanwhile, does .by_ref() work? If it doesn't, is it just the case of missing ?Sized in a couple places?

@japaric
Copy link
Member

japaric commented Jan 12, 2015

This a particular case of #20617. See comments over there. @nikomatsakis is leaning towards an opt-in derive syntax extension that handles the boiler plate code, instead of automatic impls by the compiler.

@bluss
Copy link
Member

bluss commented Jan 12, 2015

ByRef for trait objects seems to hit the same llvm assertion:

fn main() {
    struct ByRef<'r, I: ?Sized>(&'r mut I) where I: 'r;
    impl<'r, I: ?Sized> Iterator for ByRef<'r, I> where
        I: 'r + Iterator
    {
        type Item = <I as Iterator>::Item;
        fn next(&mut self) -> Option<<I as Iterator>::Item>
        {
            self.0.next()
        }
    }

    let mut it = Box::new(0..10) as Box<Iterator<Item=i32>>;
    assert_eq!(it.next(), Some(0));

    let mut jt: &mut Iterator<Item=i32> = &mut *it;
    assert_eq!(jt.next(), Some(1));

    let mut r = ByRef(jt);
    assert_eq!(r.next(), Some(2));    // No ICE without this line.
}

output:

rustc: /build/rust-git/src/rust/src/llvm/lib/IR/Instructions.cpp:1086: void llvm::StoreInst::AssertOK(): Assertion `getOperand(0)->getType() == cast<PointerType>(getOperand(1)->getType())->getElementType() && "Ptr must be a pointer to Val type!"' failed.

@BurntSushi
Copy link
Member Author

I'm not sure this is a bug at all. You're pretty much asking for an automatic impl<T> Trait for &mut T where T: Trait

Interesting. So if I have a value with type Box<T> where T is a trait, then we can't say that Box<T> implements T in the general case? (Assuming object safety.) So my guess is that Box<Iterator> can still call next because of auto deref? Shouldn't that mean it can work with for? Maybe that is what #20605 is about... You have to explicitly deref a Box<Iterator> to use it in for?

(Sorry for all the questions. I'm just confused!)

@eddyb
Copy link
Member

eddyb commented Jan 12, 2015

@BurntSushi doing autoderef on the iterator in for seems like something reasonable to have.
#20605 looks like the compiler is mistakenly treating an unsized lvalue as an rvalue, in trans.

@nikomatsakis
Copy link
Contributor

On Mon, Jan 12, 2015 at 01:33:08PM -0800, Andrew Gallant wrote:

Interesting. So if I have a value with type Box<T> where T is a
trait, then we can't say that Box<T> implements T in the general
case?

Actually, I believe it works with Box, but not with the other types.

japaric pushed a commit to japaric/rust that referenced this issue Jan 19, 2015
alexcrichton added a commit to alexcrichton/rust that referenced this issue Jan 21, 2015
closes rust-lang#20953
closes rust-lang#21361

---

In the future, we will likely derive these `impl`s via syntax extensions or using compiler magic (see rust-lang#20617). For the time being we can use these manual `impl`s.

r? @aturon
cc @BurntSushi @Kroisse
@hicqu
Copy link

hicqu commented Dec 31, 2016

Just thank you for this issue. It resolves all my problems perfectly!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-trait-system Area: Trait system
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants