Inferred type of a function assigned to an untyped variable

⚓ Rust    📅 2025-11-12    👤 surdeus    👁️ 5      

surdeus

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{...}).

3 posts - 3 participants

Read full topic

🏷️ Rust_feed