I don't understand this error message

type parameter {Q} is part of concrete type but not used in parameter list for the impl Trait type alias

and the reference seems like a rabbit hole

Can you post your code that generates the error?

a code example is here in playground

#![feature(type_alias_impl_trait)]

use std::rc::Rc;

type CallbackInner<IN, OUT> = impl Fn(IN) -> OUT;

pub struct Callback<IN, OUT = ()> {
    cb: Rc<CallbackInner<IN, OUT>>,
}

impl<IN, OUT, F: Fn(IN) -> OUT + 'static> From<F> for Callback<IN, OUT> {
    fn from(func: F) -> Self {
        Callback { cb: Rc::new(func) }
    }
}

A TAIT is supposed to refer to a specific concrete type, so that generic From impl doesn't make a lot of sense. The From impl accepts an open set of types, for this to work Callback could only be constructed only with one specific type. TAIT is generally more useful as a output than (as is in this case) an input.

1 Like

In this case, there’s not much reason to use impl Fn(…) instead of dyn Fn(…): You’re storing the closure inside an Rc, so it’s behind a pointer anyway.

use std::rc::Rc;

type CallbackInner<IN, OUT> = dyn Fn(IN) -> OUT;

pub struct Callback<IN, OUT = ()> {
    cb: Rc<CallbackInner<IN, OUT>>,
}

impl<IN, OUT, F: Fn(IN) -> OUT + 'static> From<F> for Callback<IN, OUT> {
    fn from(func: F) -> Self {
        Callback { cb: Rc::new(func) }
    }
}
2 Likes

The inputs to the TAIT must uniquely determine the output -- the aliased type. But in your playground there are multiple F that could be used to define the alias. This is possible because F is not an input to the TAIT ("not used in parameter list") even though it is part of the alias ("concrete type") .

A direct fix would be to make F an input to the TAIT.

3 Likes

Seems like the op might instead have been looking for trait aliases? I don't think it works much better here, but it makes more sense.

Hmm, like so? Perhaps, the motivation is unclear to me. If so, you can do something similar on stable.

Without implied bounds, you're going have to repeat the bounds on the F parameter everywhere anyway, so I'd be inclined to just

pub struct Callback<F> {
    cb: Rc<F>,
}

impl<F> From<F> for Callback<F> {
    fn from(func: F) -> Self {
        Callback { cb: Rc::new(func) }
    }
}

at the struct level.

1 Like

Yeah, that's what I meant by it not working much better, but if you understand the difference between trait aliases and TAIT, I doubt that you would think the OP code would work?

Honestly, thinking more on it, I think they were just trying to look for a way to spell:

pub struct Callback<IN, OUT = ()> {
    cb: Rc<impl Fn(IN) -> OUT>,
}

which is understandable, but is basically impossible. (Unless Rust just picks dyn, which I guess is technically correct)

1 Like

Yeah... probably @2e71828's reply is the closest thing to that, probably exactly what they want if they need to accept "everything" like the From implementation implies. It could be adapted to TAIT to hide the dyn Fn(In) -> Out but I don't see a point to doing so. I guess that would still be more flexible if the type is public somehow and you might wrap up the closures in something else later on.

1 Like

I assume there's an opaque type alias RFC somewhere, but I can only find TAIT by that name. I suppose newtype-ing is good enough.

https://rust-lang.github.io/rfcs/2071-impl-trait-existential-types.html
:arrow_right:
https://rust-lang.github.io/rfcs/2515-type_alias_impl_trait.html

1 Like

Yeah, that's what I found by the name "opaque types". I meant something like pub type PublicName = not_pub private::Name where nothing about PublicName leaks, apropos to:

Oh, I misunderstood, I thought you couldn't find the RFCs because it got renamed / is usually abbreviated :sweat_smile:. TAIT is the opaque alias RFC as far as I'm aware. It is a little funny you can't declare and define it in one go, but then again, self-documentation is the only real reason I can think of to do so. (If you never use it, why do you need it?)

Related: private_in_public and RFC 2145.

1 Like

I'm doing diagnostic message migration and uncapble of understanding the error message, which makes me worry.

The code was found in an issue I lost track of.

1 Like

Ah, then I would be talking about whoever wrote that code, assuming they weren't trying to produce this error!

I do think the error could be improved. I'm not sure what the bar for unstable features is though?

Perhaps something like:

No type for CallbackInner<IN, OUT> could be determined, as this expression requires it to have a parameter for F

1 Like