taiki-e / iter-enum

#[derive(Iterator, DoubleEndedIterator, ExactSizeIterator, FusedIterator, Extend)] for enums.
https://docs.rs/iter-enum
Apache License 2.0
14 stars 1 forks source link

Failed to derive `Iterator` with mixing lifetime and type generics #23

Closed lemolatoon closed 1 week ago

lemolatoon commented 1 month ago

versions and environments

$ cargo -vV
cargo 1.79.0 (ffa9cf99a 2024-06-03)
release: 1.79.0
commit-hash: ffa9cf99a594e59032757403d4c780b46dc2c43a
commit-date: 2024-06-03
host: aarch64-apple-darwin
libgit2: 1.7.2 (sys:0.18.3 vendored)
libcurl: 8.4.0 (sys:0.4.72+curl-8.6.0 system ssl:(SecureTransport) LibreSSL/3.3.6)
ssl: OpenSSL 1.1.1w  11 Sep 2023
os: Mac OS 14.3.0 [64-bit]

$ cat Cargo.lock | grep -A 2 -B 1 iter-enum
[[package]]
name = "iter-enum"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
--
dependencies = [
 "iter-enum",
]

light description

I failed to compile enum deriving Iterator, where one field has lifetime parameter, and the other has type generics. Depending on the order of fields, compile can be succeed.

detailed description

I found the weird bug. Let's say I write the code below.

use iter_enum::Iterator;

pub struct A<T>(T);
pub struct B<'a>(pub &'a ());

impl<T> Iterator for A<T> {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        Some(0)
    }
}

impl<'a> Iterator for B<'a> {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        Some(0)
    }
}

#[derive(Iterator)]
enum Enum<'a, T> {
    B(B<'a>),
    A(A<T>),
}

fn main() {}

This can be compiled, but If I switch the enum field, this suddenly won't be compiled.

use iter_enum::Iterator;

pub struct A<T>(T);
pub struct B<'a>(pub &'a ());

impl<T> Iterator for A<T> {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        Some(0)
    }
}

impl<'a> Iterator for B<'a> {
    type Item = usize;

    fn next(&mut self) -> Option<Self::Item> {
        Some(0)
    }
}

#[derive(Iterator)]
enum Enum<'a, T> {
    A(A<T>), // switch !
    B(B<'a>),
}

fn main() {}

Actual Compile Error ↓

error[E0308]: `match` arms have incompatible types
  --> src/main.rs:22:10
   |
22 | #[derive(Iterator)]
   |          ^^^^^^^^
   |          |
   |          expected `Option<<... as Iterator>::Item>`, found `Option<usize>`
   |          this is found to be of type `Option<<A<T> as Iterator>::Item>`
   |          `match` arms have incompatible types
   |
   = note: expected enum `Option<<A<T> as Iterator>::Item>`
              found enum `Option<usize>`
   = help: consider constraining the associated type `<A<T> as Iterator>::Item` to `usize` or calling a method that returns `<A<T> as Iterator>::Item`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html
   = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: a value of type `__U` cannot be built from an iterator over elements of type `usize`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ value of type `__U` cannot be built from `std::iter::Iterator<Item=usize>`
     |
note: required by a bound in `collect`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2000:19
     |
2000 |     fn collect<B: FromIterator<Self::Item>>(self) -> B
     |                   ^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::collect`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: expected a `FnMut(&usize)` closure, found `__F`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ expected an `FnMut(&usize)` closure, found `__F`
     |
     = note: expected a closure with arguments `(&<A<T> as Iterator>::Item,)`
                found a closure with arguments `(&usize,)`
note: required by a bound in `partition`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2190:12
     |
2186 |     fn partition<B, F>(self, f: F) -> (B, B)
     |        --------- required by a bound in this associated function
...
2190 |         F: FnMut(&Self::Item) -> bool,
     |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::partition`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: the trait bound `__U: Extend<usize>` is not satisfied
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ the trait `Extend<usize>` is not implemented for `__U`
     |
note: required by a bound in `partition`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2189:22
     |
2186 |     fn partition<B, F>(self, f: F) -> (B, B)
     |        --------- required by a bound in this associated function
...
2189 |         B: Default + Extend<Self::Item>,
     |                      ^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::partition`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: expected a `FnMut(__U, usize)` closure, found `__F`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ expected an `FnMut(__U, usize)` closure, found `__F`
     |
     = note: expected a closure with arguments `(_, <A<T> as Iterator>::Item)`
                found a closure with arguments `(_, usize)`
note: required by a bound in `fold`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2584:12
     |
2581 |     fn fold<B, F>(mut self, init: B, mut f: F) -> B
     |        ---- required by a bound in this associated function
...
2584 |         F: FnMut(B, Self::Item) -> B,
     |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::fold`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: expected a `FnMut(usize)` closure, found `__F`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ expected an `FnMut(usize)` closure, found `__F`
     |
     = note: expected a closure with arguments `(<A<T> as Iterator>::Item,)`
                found a closure with arguments `(usize,)`
note: required by a bound in `all`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2752:12
     |
2749 |     fn all<F>(&mut self, f: F) -> bool
     |        --- required by a bound in this associated function
...
2752 |         F: FnMut(Self::Item) -> bool,
     |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::all`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: expected a `FnMut(usize)` closure, found `__F`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ expected an `FnMut(usize)` closure, found `__F`
     |
     = note: expected a closure with arguments `(<A<T> as Iterator>::Item,)`
                found a closure with arguments `(usize,)`
note: required by a bound in `any`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2806:12
     |
2803 |     fn any<F>(&mut self, f: F) -> bool
     |        --- required by a bound in this associated function
...
2806 |         F: FnMut(Self::Item) -> bool,
     |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::any`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: expected a `FnMut(&usize)` closure, found `__P`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ expected an `FnMut(&usize)` closure, found `__P`
     |
     = note: expected a closure with arguments `(&<A<T> as Iterator>::Item,)`
                found a closure with arguments `(&usize,)`
note: required by a bound in `find`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2870:12
     |
2867 |     fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
     |        ---- required by a bound in this associated function
...
2870 |         P: FnMut(&Self::Item) -> bool,
     |            ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::find`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: expected a `FnMut(usize)` closure, found `__F`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ expected an `FnMut(usize)` closure, found `__F`
     |
     = note: expected a closure with arguments `(<A<T> as Iterator>::Item,)`
                found a closure with arguments `(usize,)`
note: required by a bound in `find_map`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:2902:12
     |
2899 |     fn find_map<B, F>(&mut self, f: F) -> Option<B>
     |        -------- required by a bound in this associated function
...
2902 |         F: FnMut(Self::Item) -> Option<B>,
     |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::find_map`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0277]: expected a `FnMut(usize)` closure, found `__P`
    --> src/main.rs:22:10
     |
22   | #[derive(Iterator)]
     |          ^^^^^^^^ expected an `FnMut(usize)` closure, found `__P`
     |
     = note: expected a closure with arguments `(<A<T> as Iterator>::Item,)`
                found a closure with arguments `(usize,)`
note: required by a bound in `position`
    --> /Users/lemolatoon/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/iterator.rs:3044:12
     |
3041 |     fn position<P>(&mut self, predicate: P) -> Option<usize>
     |        -------- required by a bound in this associated function
...
3044 |         P: FnMut(Self::Item) -> bool,
     |            ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Iterator::position`
     = note: this error originates in the derive macro `Iterator` (in Nightly builds, run with -Z macro-backtrace for more info)

Some errors have detailed explanations: E0277, E0308.
For more information about an error, try `rustc --explain E0277`.
error: could not compile `tmp` (bin "tmp") due to 13 previous errors
taiki-e commented 1 month ago

At first glance, it sounds like a compiler bug that lazily resolves associated types of types containing generics.

lemolatoon commented 1 month ago

@taiki-e Thank you for your quick response!

I tried checking expanded one.

impl<'a, T> ::core::iter::Iterator for Enum<'a, T>
where
    A<T>: ::core::iter::Iterator,
{
    type Item = <A<T> as ::core::iter::Iterator>::Item;
    #[inline]
    fn next(&mut self) -> ::core::option::Option<Self::Item> {
        match self {
            Enum::A(x) => <A<T> as ::core::iter::Iterator>::next(x),
            Enum::B(x) => <B<'a> as ::core::iter::Iterator>::next(x),
        }
    }
    // Other methods follows
}

This normal code emits a little easy to see error messages.

error[E0308]: `match` arms have incompatible types
  --> src\expanded.rs:33:27
   |
31 | /         match self {
32 | |             Enum::A(x) => <A<T> as ::core::iter::Iterator>::next(x),
   | |                           ----------------------------------------- this is found to be of type `Option<<expanded::A<T> as Iterator>::Item>`
33 | |             Enum::B(x) => <B<'a> as ::core::iter::Iterator>::next(x),
   | |                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Option<<A<T> as Iterator>::Item>`, found `Option<usize>`
34 | |         }
   | |_________- `match` arms have incompatible types
   |
   = note: expected enum `Option<<expanded::A<T> as Iterator>::Item>`
              found enum `Option<usize>`
   = help: consider constraining the associated type `<expanded::A<T> as Iterator>::Item` to `usize` or calling a method that returns `<expanded::A<T> as Iterator>::Item`
   = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html

Now I am confident that this is not the bug of the derive macro, but compiler's bug or limitation.

Do you think is this compiler's bug? I will also check rustc's issues about this.


The way I produced the expanded one (iter_enum::lib.rs, derive_iterator) ↓

let tokens: TokenStream = quick_derive! { ... };
println!("{}", tokens.clone().to_string());
tokens
taiki-e commented 1 week ago

Closing as a compiler bug.