1
use std::sync::Arc;
pub type A = Arc<dyn Fn(dyn FnOnce(&mut [u8]), usize) -> Result<(), ()> + Send + Sync>;

pub struct B {
    a: A,
}

Gives

   Compiling playground v0.0.1 (/playground)
error[E0277]: the size for values of type `(dyn for<'r> FnOnce(&'r mut [u8]) + 'static)` cannot be known at compilation time
 --> src/lib.rs:5:8
  |
5 |     a: A,
  |        ^ doesn't have a size known at compile-time
  |
  = help: the trait `Sized` is not implemented for `(dyn for<'r> FnOnce(&'r mut [u8]) + 'static)`
  = note: only the last element of a tuple may have a dynamically sized type

I think Arc has a size know at compile time. dyn Fn has, at least when I do pub type A = Arc<dyn Fn() -> Result<(), ()> + Send + Sync>;. However, when I put dyn FnOnce(&mut [u8]) inside dyn Dn, the size cannot be known.

Why pub type A = Arc<dyn Fn() -> Result<(), ()> + Send + Sync>; is ok but not pub type A = Arc<dyn Fn(dyn FnOnce(&mut [u8]), usize) -> Result<(), ()> + Send + Sync>;?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Gatonito
  • 1,662
  • 5
  • 26
  • 55

2 Answers2

1

The error is a little unhelpful because it's directing you to the wrong part of the type.

dyn Fn has [a size]

Like any "bare" trait object, dyn Fn is not sized. However this is ok because Arc<T> does not require T: Sized.

The issue is that dyn FnOnce(&mut [u8]) is unsized, so the you can't have Fn(dyn FnOnce(&mut [u8]), usize). It is not allowed for a function argument to be unsized.

Making that function argument Sized will fix the problem, e.g.

pub type A = Arc<dyn Fn(&dyn FnOnce(&mut [u8]), usize) -> Result<(), ()> + Send + Sync>;
//                      ^--- added &

It's worth reporting a bug, so that this error message can be improved.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • I think this is just [Trait bounds are not checked on type aliases until they are used](https://github.com/rust-lang/rust/issues/51626). – trent Mar 11 '21 at 13:09
  • 1
    @trentcl Maybe, but see [here](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=a9dd190bf7b8d94d31fda5c1ab24b66a). The error message underlines the entire type, not just the inner `FnOnce`. – Peter Hall Mar 11 '21 at 14:08
  • 1
    While `&dyn FnOnce(...)` compiles as a type definition, you won't be able to actually _call_ the inner closure because calling a `FnOnce` needs to consume the closure, which is impossible if it's behind a reference. Possible solutions (that I'm aware of) are outlined in [this answer](https://stackoverflow.com/a/66579120/1600898) to the OP's other question the OP explains the intended usage of the type. – user4815162342 Mar 11 '21 at 18:36
0

error messages (rust 1.50)

help: the trait `Sized` is not implemented for `(dyn for<'r> FnOnce(&'r mut [u8]) + 'static)`
note: only the last element of a tuple may have a dynamically sized type

FnOnce trait takes Args as generic type and Args may be converted from tuple internally (my guess :).

but, we can't make tuple like (dynamic sized, sized)

Your code can be fixed using &dyn FnOnce (which is sized) or swap argument positions

pub type A = Arc<dyn Fn(&dyn FnOnce(&mut [u8]), usize) -> Result<(), ()> + Send + Sync>;
// or
pub type A = Arc<dyn Fn(usize, dyn FnOnce(&mut [u8])) -> Result<(), ()> + Send + Sync>;

jongguk.jo
  • 96
  • 3