"type parameter is never used" despite being used in type alias' trait bound?

I have this type alias to pass a FnMut closure:

struct State { /* ... */ }

struct Message<A, B> { /* ... */ }

type ModifyState<ActingFn, Fut> 
where
    ActingFn: FnMut (&mut State) -> Fut,
    Fut: Future<Output = ()> 
    = Message<ActingFn, ()> ;

I'm getting type parameter 'Fut' is never used - consider removing 'Fut' or referring to it in the body of the type alias, though it is used in the trait bound. Is this a bug and is there a way to bypass it?

On stable, this appears to require either boxing or a concrete type. Here's how you might express this with boxing:

type ModifyStateFut<'fut> = Pin<Box<dyn Future<Output = ()> + 'fut>>;

type ModifyState<ActingFn>
where
    ActingFn: FnMut (&mut State) -> ModifyStateFut<'_>,
= Message<ActingFn, ()>;

Using this currently gives a warning:

warning: where clauses on type aliases are not enforced
  --> src/lib.rs:20:5
   |
19 | / where
20 | |     ActingFn: AsyncFnMut(&mut State),
   | |_____^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: remove this where clause
   |       |
   |       will not be checked at usage sites of the type alias
   |
   = note: this is a known limitation of the type checker that may be lifted in a future edition.
           see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
   = note: `#[warn(type_alias_bounds)]` on by default

Tracking issue for lazy type aliases · Issue #112792 · rust-lang/rust

On nightly, the warning is slightly different:
warning: where clauses on type aliases are not enforced
  --> src/lib.rs:19:5
   |
18 | / where
19 | |     ActingFn: AsyncFnMut(&mut State),
   | |_____^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- help: remove this where clause
   |       |
   |       will not be checked at usage sites of the type alias
   |
   = note: this is a known limitation of the type checker that may be lifted in a future edition.
           see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
   = help: add `#![feature(lazy_type_alias)]` to the crate attributes to enable the desired semantics
   = note: `#[warn(type_alias_bounds)]` on by default

Enabling #![feature(lazy_type_alias)] requires changing the type alias syntax to put the where clause at the end pointing to Proposal: Change syntax of where clauses on type aliases · Issue #89122 · rust-lang/rust.

I did not explore this path any further, there may be dragons.

It looks like AsyncFnMut might be what you want (currently available on the beta channel, scheduled for stable release in 1.85.0 in about one week). You can use it on beta easily, but it still gives the same warning about unenforced where clauses on type aliases.

type ModifyState<ActingFn>
where
    ActingFn: AsyncFnMut(&mut State),
= Message<ActingFn, ()>;

Trait bounds on type aliases have no effect. There is a type_alias_bounds lint which warns about it, but you don't get the warning due to a compiler error.

Also, usage of a type only in trait bounds isn't considered "being used". You need to actually have the type as a field of the type, or a transitive field, or being part of a concrete type which is a transitive field (e.g. *mut T or fn() -> T). If the type isn't part of your data, you need to include a PhantomData field with a proper generic parameter, depending on T. E.g. if you expect to "produce" values of Fut, you need to include something like PhantomData<fn() -> Fut> in your type.

2 Likes

It is if it ends up being constrained, which is the case in the OP -- ActingFn is in the alias, and Fut is the return type which is equivalent to an associated type equality bound with ActingFn as the implementer. So it works with lazy_type_alias or as a struct on stable.

1 Like

I was not aware of AsyncFnMut, sounds like it directly solves the problem here. Will be waiting for its release then. Thank you!