Rust: Cleanup: Use `#![feature(associated_type_bounds)]` where applicable

Created on 11 Jun 2019  路  14Comments  路  Source: rust-lang/rust

We can now write bounds of form:

T: MyTrait<AssociatedType: OtherTrait>,

When you find bounds of form:

T: MyTrait,
T::AssociatedType: OtherTrait,
// or, but less commonly:
<T as MyTrait>::AssociatedType: OtherTrait,

You can rewrite them to the first form (but you'll need to add the feature gate...).

One regex you can try is: ::\w+: \w+ (doesn't cover lifetimes).

This is relevant both for the standard library and throughout the compiler.
Clippy may also want to do this and possibly also add an experimental lint? cc @oli-obk

cc https://github.com/rust-lang/rust/issues/52662


This issue has been assigned to @iluuu1994 via this comment.


C-cleanup E-easy E-help-wanted F-associated_type_bounds T-compiler

Most helpful comment

@Centril Sorry, I need to get the PR that fixes that bug merged soon. Niko left some feedback which I should address. Pester me tomorrow or the day after if I still haven't done it.

All 14 comments

Shouldn't this wait for the feature to reach beta?
(This would be an annoying thing to alternate on #[cfg(bootstrap)].)

Either works for me.

@rustbot claim

I'll implement this now, you can decide whether you want to merge it now or wait until it's stabilized. We could also make an issue to remove the #![feature(associated_type_bounds)] once the feature is stabilized.

Do you guys prefer:

impl<T> Clone for ...<T>
    where T: IntoIterator<IntoIter: Clone>

or

impl<T: IntoIterator<IntoIter: Clone>> Clone for ...<T>

I like for former better.

@iluuu1994 The first one should be:

impl<T> Clone for ...<T>
where
    T: IntoIterator<IntoIter: Clone>,

per rustfmt.

which one you use is situational I think; I'd use the latter if it cleanly fits on one line and there are not a lot of bounds and the former otherwise.

@Centril

Is this one expected to fail?

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=81d86cad842d74f4307d62b4e5ab1a49

pub struct Flatten<I>
where
    I: Iterator,
    I::Item: IntoIterator,
{
    inner: I::Item::IntoIter,
}
error[E0223]: ambiguous associated type
 --> src/lib.rs:6:12
  |
6 |     inner: I::Item::IntoIter,
  |            ^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<<I as std::iter::Iterator>::Item as Trait>::IntoIter`

Not sure how I::Item is ambiguous.

Yeah that's ambiguous.

Additionally, switching to associated type bounds requires more as casts:

Without associated type bounds this is ok:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=a3dba78b4b8af6a3710dc3351b8e2b0a

pub struct Flatten<I>
where
    I: Iterator,
    I::Item: IntoIterator,
{
    inner: <I::Item as IntoIterator>::IntoIter,
}

This one isn't ok:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d608b0e4b2a9b0f2bd4abfb06bc492ac

#![feature(associated_type_bounds)]

pub struct Flatten<I>
where
    I: Iterator<Item: IntoIterator>,
{
    inner: <I::Item as IntoIterator>::IntoIter,
}
error[E0221]: ambiguous associated type `Item` in bounds of `I`
 --> src/lib.rs:7:13
  |
7 |     inner: <I::Item as IntoIterator>::IntoIter,
  |             ^^^^^^^ ambiguous associated type `Item`
  |
note: associated type `I` could derive from `std::iter::IntoIterator`
 --> src/lib.rs:7:13
  |
7 |     inner: <I::Item as IntoIterator>::IntoIter,
  |             ^^^^^^^
note: associated type `I` could derive from `std::iter::Iterator`
 --> src/lib.rs:7:13
  |
7 |     inner: <I::Item as IntoIterator>::IntoIter,
  |             ^^^^^^^

This one is ok:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=aea5544d3d7e4163af7d28402434701b

#![feature(associated_type_bounds)]

pub struct Flatten<I>
where
    I: Iterator<Item: IntoIterator>,
{
    inner: <<I as Iterator>::Item as IntoIterator>::IntoIter,
}

Note the <I as Iterator> .

Yeah that's ambiguous.

How so? Can't I just be an Iterator which only has one associated type Item? Please note I'm not questioning your answer, I just don't understand it.

This one isn't ok:

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d608b0e4b2a9b0f2bd4abfb06bc492ac

#![feature(associated_type_bounds)]

pub struct Flatten<I>
where
    I: Iterator<Item: IntoIterator>,
{
    inner: <I::Item as IntoIterator>::IntoIter,
}

This seems similar to the bug in https://github.com/rust-lang/rust/issues/61752 :(
cc @alexreg

How so? Can't I just be an Iterator which only has one associated type Item? Please note I'm not questioning your answer, I just don't understand it.

Honestly I don't really sure why that is the case but it has been ambiguous since forever. :)

Honestly I don't really sure why that is the case but it has been ambiguous since forever. :)

Haha ok that works for me 馃檪

@Centril Sorry, I need to get the PR that fixes that bug merged soon. Niko left some feedback which I should address. Pester me tomorrow or the day after if I still haven't done it.

Okay, https://github.com/rust-lang/rust/pull/61919 is done, just waiting on review & merge. :-)

Great! That was the only issue I found with the associated_type_bounds feature. I'll rebase and remove the then unneeded workarounds after this has been merged. Thanks @Centril and @alexreg!

Was this page helpful?
0 / 5 - 0 ratings