Rust: Error extending Fn trait then using it as a trait object: the value of the associated type `Output must be specified

Created on 3 Apr 2015  路  17Comments  路  Source: rust-lang/rust

trait Foo: Fn(i32) + Send { }
impl<T:?Sized + Fn(i32) + Send> Foo for T { }

fn wants_foo(t: Box<Foo>) {
}

fn main() {
  let f = Box::new(|x| println!("{}", x));
  wants_foo(f);
}

Output:

<anon>:9:13: 9:14 error: the value of the associated type `Output` (from the trait `core::ops::FnOnce`) must be specified [E0191]
<anon>:9   wants_foo(f);
                     ^

cc @nikomatsakis

A-associated-items A-traits C-bug

Most helpful comment

Is it going to be fixed in any upcoming version?

All 17 comments

The problem is that the associated type is defined in a supertrait, and we don't consider that case when we check that the object type is well-formed.

It can be quite painful to work around this problem, as it's the only way to create aliases for traits.

When you have bounds such as the following scattered all over the code: Fn(&(Any + Send), &'static str, u32) + 'static, it's _much_ nicer to be able to give it a short name.

@Diggsey: what workaround would you propose? I've been hitting my head against this wall for a while now, and am getting nowhere..

@jonhoo I don't know about your particular use-case, but for me I was using this to create a short alias for a trait - the workaround was just to use the long name everywhere, ie. Fn(&(Any + Send), &'static str, u32) + 'static

My use-case is exactly the same. I was hoping I might be able to use a macro that expanded to the type, but that doesn't seem to work either. I suppose I'll just have to use the full signature for now..

@nikomatsakis Why is that case not considered?

@Kimundi it's a bug, really.

Ah, okay it sounded like that was intentional :)

Is it going to be fixed in any upcoming version?

Note that @durka points out in #29328 this does technically allow one to violate some stability restrictions, but probably not in a way that matters:

trait FnAlias: Fn() {}

fn main() {
    let _: FnAlias;            // error
    let _: FnAlias<Output=()>; // no error, but I shouldn't be able to do this!
}

This bug is very annoying. I have the same use case as @Diggsey and @jonhoo: creating an alias of a trait with cumbersome bounds that I don't want to have to repeat everywhere.

In case it's not obvious from the title, this doesn't have to do with the Fn trait specifically. It's just about supertrait associated types being ignored when using the subtrait. Here's a simpler illustration:

trait A {
    type Assoc;
    // Pretend there are several more associated types here to make uses of `Box<A>` inconvenient.
}

trait B: A<Assoc=()> {}

fn takes_b(b: Box<B>) {}

which results in:

error[E0191]: the value of the associated type `Assoc` (from the trait `A`) must be specified
 --> src/lib.rs:8:19
  |
8 | fn takes_b(b: Box<B>) {}
  |                   ^ missing associated type `Assoc` value

The compiler should be able to infer that type Assoc = () here.

use std::iter::Iterator;

pub trait LeapfrogIterator<T, V> : Iterator<Item=(T,V)> {
    fn next_above(&mut self, &T) -> Option<(T, V)>;
}

fn main () {
    let v: Box<LeapfrogIterator<i64, i64>> = unimplemented!();
}

https://is.gd/VcQmki

is another concrete use case - if I want to extend Iterator in this way, I need to write LeapfrogIterator<K, V, Item=(K, V)> every time I want to talk about the trait, even though this is the only legal value for Item to take on. (This doesn't express the bug in a new way, but is an example I ran into organically and eventually found this bug due to.)

I hit this when trying to create an alias of a FnMut trait. Using a macro still doesn't work as @jonhoo found two years ago, e.g. https://is.gd/h9CZ8H, because trait bounds don't seem to accept macro invocations.

@nikomatsakis

The problem is that the associated type is defined in a supertrait, and we don't consider that case when we check that the object type is well-formed.

@Kimundi it's a bug, really.

Is it possible to give some mentoring hints for fixing this?

I think this is the same as #23856.

@mbrubeck I think so too. Have we confirmed it yet? If so, worth closing this as duplicate.

Okay, we have a fix! Waiting for review and merge on https://github.com/rust-lang/rust/pull/55687.

Was this page helpful?
0 / 5 - 0 ratings