Inferred type of a function assigned to an untyped variable

I thought that, unlike closures, functions have well-defined types, like fn(), which is the same as fn() -> (), fn(bool, u8) -> (bool, u16) etc . (And similar for unsafe fn, like unsafe fn(), unsafe fn(bool, u8) -> (bool, u16) etc.)

But, when I assign a function identifier/path to an untyped variable, it has some other (unique?) type, as mentioned in this error:

no method named use_it found for fn item fn() {zero_args_unit} in the current scope

pub trait ZeroArgsUnitFnTrait {
    fn use_it(&self) {}
}

type ZeroArgsUnitFnType = fn();
impl ZeroArgsUnitFnTrait for ZeroArgsUnitFnType  {}

fn zero_args_unit() {}

// Compiles
fn assign_fn_to_typed_var() {
    let f: fn() -> () = zero_args_unit;
    f.use_it();

    let f: ZeroArgsUnitFnType = zero_args_unit;
    f.use_it();
}

// Fails to compile
fn assign_fn_to_untyped_var() {
    let f = zero_args_unit;
    f.use_it();
}

// Fails to compile
fn direct_no_assign() {
    zero_args_unit.use_it();
}

Are those actual unnamed types accessible somehow, or can I at least implement trait(s) for them somehow (ideally separately for safe and unsafe ones, or just limiting to safe ones)? Or what are such types called and where can I read about them?

Or, a more specialized problem, please: How can I detect at compile time (in macro_rules!) whether a given function is safe (rather than unsafe), but without a compiler error. Or, rather, how do I ensure that a given function actually is not safe, but unsafe (and issue a compile error is the function is safe)? (I cannot use #[forbid(unused_unsafe)] and then unsafe {...}, because instead of a function identifier/path I may be given an expression that yields the function, and the actual expression itself may include unsafe{...}).

See Function item types - The Rust Reference

1 Like

You can't name function item types directly, but you can implement for a generic F: Fn() or similar. I'm fairy certain that would be the safe ones only -- I'm on mobile currently but it would be easy to confirm.

Function item types are unique, like closure types, and zero sized, like non-capturing closures. In contrast types like fn() are function pointers.

1 Like

Obligatory link to Logan Smith's Rust Functions Are Weird (But Be Glad) video that goes in depth into why function items have different types and what optimisations this enables.