diesel-rs/diesel · error · syn::Error

function body should not be empty for auto_type

Error message

function body should not be empty for auto_type

What it means

#[auto_type] needs at least one statement in the function body: it inspects the last statement to determine the return type and build the type alias. An empty body (`fn f() -> _ {}`) leaves `block.stmts.last()` as None, so the macro errors with this message instead of silently generating nothing.

Solutions

  1. Add at least one expression statement / return expression to the function body.
  2. Remove #[auto_type] from the empty stub until the body is implemented.
  3. Give the function a concrete return type and drop the macro if it must remain empty.

Example fix

// before
#[auto_type]
fn f() -> _ {}
// after
#[auto_type]
fn f() -> _ { 0i32 }
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_nonempty(body: &[syn::Stmt]) -> Result<(), ()> { if body.is_empty() { Err(()) } else { Ok(()) } }

Prevention

When it happens

Trigger: `#[auto_type] fn f() -> _ {}` — a function whose block contains no statements at all.

Common situations: Scaffolding a stub function and adding #[auto_type] before writing the body; or commenting out the entire body while keeping the attribute during debugging.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of diesel-rs/diesel@6fa6ed01b2 (2026-09-07). Data as JSON: /api/errors/2c1c3a81b86de016. Report an issue: GitHub.

Appendix: source

Thrown at dsl_auto_type/src/auto_type/mod.rs:122

    let last_statement = input_function.block.stmts.last().ok_or_else(|| {
        syn::Error::new(
            input_function.span(),
            "function body should not be empty for auto_type",
        )
    })?;
    let mut errors = Vec::new();
    let return_type = match input_function.sig.output {
        syn::ReturnType::Type(_, return_type) => {
            let return_expression = match last_statement {
                syn::Stmt::Expr(expr, None) => expr,
                syn::Stmt::Expr(
                    syn::Expr::Return(syn::ExprReturn {
                        expr: Some(expr), ..
                    }),
                    _,
                ) => &**expr,
                _ => {
                    return Err(syn::Error::new(
                        last_statement.span(),
                        "last statement should be an expression for auto_type",
                    )
                    .into());
                }
            };

            // Build a map of local variables, and get the function parameters in there
            let mut local_variables_map = LocalVariablesMap {
                inferrer_settings: &inferrer_settings,
                inner: LocalVariablesMapInner {
                    map: Default::default(),
                    parent: None,
                },
            };
            for const_generic in input_function.sig.generics.const_params() {
                local_variables_map.process_const_generic(const_generic);
            }

View on GitHub (pinned to 6fa6ed01b2)