Associated type bounds on impl Trait in return position

Impl Trait in argument position can be replaced with a bounded generic parameter, so the following are equivalent:

fn f<T       >(_: impl A + B) {}
fn f<T: A + B>(_: T         ) {}

Can something similar be done with impl Trait in return position? The obvious thing doesn't work:

fn b<T: Clone + Copy>() -> T { 42 }
error[E0308]: mismatched types
 --> src/bin/return_impl_trait.rs:2:32
  |
2 | fn b<T: Clone + Copy>() -> T { 42 }
  |      -                     -   ^^ expected type parameter `T`, found integer
  |      |                     |
  |      |                     expected `T` because of return type
  |      this type parameter   help: consider using an impl return type: `impl Clone + Copy`

It would be nice to have, if not strictly necessary, when many bounds accumulate on the return type. But if a bound needs to be placed on a returned trait's associated type, can it be done with impl Trait in return position at all?

Here's a minimal example of the problem:

/// A function with bounds on generic parameter's associated type
fn take<T>(_: T)
where
    T: Iterator,
    T::Item: Copy, // How can this requirement be satisfied by `make` below?
{}

/// A function which returns something that can be passed to `take`
fn make() -> impl Iterator /* what about Item: Copy? */ { 0..42 }

fn main() {
    take(make());
}

playground

How can we express the fact that make returns an iterator whose items are Copy?

Note: This is a minimal example whose purpose is to generate the relevant compiler error with trivial code: in real life I need to do something much more complex than return a range, so solutions along the lines of

fn make() -> std::ops::Range<u32> { 0..42 }

which address the irrelevant details of the toy example, are not what this question is about.

I don't know the exact rules for impl Trait with associated types, but your example problem compiles if you set Item = impl Copy:

/// A function with bounds on generic parameter's associated type
fn take<T>(_: T)
where
    T: Iterator,
    T::Item: Copy, // How can this requirement be satisfied by `make` below?
{
}

/// A function which returns something that can be passed to `take`
fn make() -> impl Iterator<Item = impl Copy> {
    0..42
}

fn main() {
    take(make());
}

Playground.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.