Functions

IrFunction is the body-bearing function shape used both for standalone functions on IrModule.functions and for impl methods on IrImpl.functions. IrFunctionSig is the body-less shape used for trait-required methods on IrTrait.methods.

IrFunction

#![allow(unused)]
fn main() {
pub struct IrFunction {
    /// Function name
    pub name: String,

    /// Generic type parameters declared on the function itself
    /// (e.g. `fn identity<T>(x: T) -> T`). Empty for impl methods;
    /// method-level generics aren't yet supported; enclosing-type
    /// generics live on the containing `IrImpl` / `IrStruct`.
    pub generic_params: Vec<IrGenericParam>,

    /// Parameters (first is `self` for methods; no `self` for standalone functions)
    pub params: Vec<IrFunctionParam>,

    /// Return type (None = unit/void)
    pub return_type: Option<ResolvedType>,

    /// Function body expression (None for extern functions)
    pub body: Option<IrExpr>,

    /// Calling convention when the function is `extern`. `None` for
    /// regular functions; `Some(ExternAbi::C)` for `extern fn` /
    /// `extern "C" fn`; `Some(ExternAbi::System)` for
    /// `extern "system" fn`.
    pub extern_abi: Option<ExternAbi>,

    /// Codegen-hint attributes (`inline`, `no_inline`, `cold`)
    /// declared as keyword prefixes before `fn`.
    pub attributes: Vec<FunctionAttribute>,

    /// Joined `///` doc comments preceding this function.
    pub doc: Option<String>,
}

impl IrFunction {
    /// Whether this function is declared `extern`. Convenience
    /// wrapper over `extern_abi.is_some()`.
    pub const fn is_extern(&self) -> bool;
}
}

IrFunctionSig

A signature-only function declaration (no body). Used for required methods declared in traits.

#![allow(unused)]
fn main() {
pub struct IrFunctionSig {
    /// Function name
    pub name: String,

    /// Parameters (first is typically `self`)
    pub params: Vec<IrFunctionParam>,

    /// Return type (None = unit/void)
    pub return_type: Option<ResolvedType>,

    /// Codegen-hint attributes (`inline`, `no_inline`, `cold`).
    pub attributes: Vec<FunctionAttribute>,
}
}

IrFunctionParam

#![allow(unused)]
fn main() {
pub struct IrFunctionParam {
    /// Parameter name
    pub name: String,

    /// Parameter type (None for bare `self`)
    pub ty: Option<ResolvedType>,

    /// Default value expression, if any
    pub default: Option<IrExpr>,

    /// Parameter passing convention
    pub convention: ParamConvention,
}
}

ParamConvention in the IR

ParamConvention is re-exported from formalang::ast. Backends should interpret it as follows:

VariantMeaning for the backend
LetImmutable read access. The backend may pass by reference or copy.
MutExclusive mutable access. The backend must ensure no aliasing.
SinkOwnership transfer. The value is logically moved; the caller cannot use it after this call.

All three conventions use identical call syntax in FormaLang source; the distinction is purely semantic. Backends that target languages with explicit ownership (Rust, C++ move semantics, Swift inout) should map directly. Backends targeting garbage-collected languages (TypeScript, Python) may treat all three as pass-by-value and ignore the distinction.

#![allow(unused)]
fn main() {
use formalang::ast::ParamConvention;

fn emit_param(param: &IrFunctionParam) {
    match param.convention {
        ParamConvention::Let  => { /* pass by value / reference */ }
        ParamConvention::Mut  => { /* pass as mutable / inout */ }
        ParamConvention::Sink => { /* consume / move */ }
    }
}
}

ExternAbi

The FFI calling convention of an extern function.

#![allow(unused)]
fn main() {
pub enum ExternAbi {
    C,       // `extern fn` (default) or `extern "C" fn`
    System,  // `extern "system" fn`  (stdcall on Win32 x86, C elsewhere)
}
}

Unknown ABI strings (extern "rustcall" fn ...) are rejected at parse time. A backend-side mapping by function name still owns symbol-name overrides and type marshalling rules across the FFI boundary.

FunctionAttribute

#![allow(unused)]
fn main() {
pub enum FunctionAttribute {
    Inline,    // `inline fn`
    NoInline,  // `no_inline fn`
    Cold,      // `cold fn`
}
}

Source syntax stacks freely with pub and extern: pub cold extern fn abort() -> Never. The frontend passes attributes through unchanged; backends decide whether to honour them.