{"record":{"id":"4192b723dc1d6c8f","repo":"risingwavelabs/risingwave","slug":"multiple-arguments-are-not-supported-for-non-optio","errorCode":null,"errorMessage":"multiple arguments are not supported for non-option function","messagePattern":"multiple arguments are not supported for non-option function","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/expr/macro/src/gen.rs","lineNumber":1007,"sourceCode":"                        quote! {{\n                            let state = self.function.create_state();\n                            #next_state\n                        }}\n                    } else {\n                        quote! {{\n                            let state = #state_type::default();\n                            #next_state\n                        }}\n                    };\n                    next_state = quote! {\n                        match (state, v0) {\n                            (Some(state), Some(v0)) => #next_state,\n                            (None, Some(v0)) => #first_state,\n                            (state, None) => state,\n                        }\n                    };\n                }\n                _ => todo!(\"multiple arguments are not supported for non-option function\"),\n            }\n        }\n        let update_state = if custom_state.is_some() {\n            quote! { _ = #next_state; }\n        } else {\n            quote! { state = #next_state; }\n        };\n        let get_result = if custom_state.is_some() {\n            quote! { Ok(state.downcast_ref::<#state_type>().into()) }\n        } else if let AggregateFnOrImpl::Impl(impl_) = user_fn\n            && impl_.finalize.is_some()\n        {\n            quote! {\n                let state = match state.as_datum() {\n                    Some(s) => s.as_scalar_ref_impl().try_into().unwrap(),\n                    None => return Ok(None),\n                };\n                Ok(Some(self.function.finalize(state).into()))","sourceCodeStart":989,"sourceCodeEnd":1025,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/macro/src/gen.rs#L989-L1025","documentation":"This panic comes from the `#[function]` macro's aggregate/codegen builder in src/expr/macro/src/gen.rs. When generating the state-transition expression for an aggregate whose underlying function is not written over `Option<T>` arguments, the macro only supports single-argument forms; a multi-argument (two-or-more params) non-option function hits a `todo!()` placeholder, deliberately aborting expansion. It signals an unsupported codegen case, not a runtime fault.","triggerScenarios":"Declaring an aggregate (e.g. via `#[aggregate]` / generate_aggregate_descriptor) whose `accumulate`-style function takes 2+ arguments and whose signature is not the `Option<T>`-argument form the macro handles (Some/None match arms). Any `#[function(\"agg(...) ...\")]` aggregate built from a multi-arg plain (non-Option) function.","commonSituations":"Contributors adding a new SQL aggregate function in RisingWave write a plain multi-argument Rust function and mark it as an aggregate; older macro versions only implemented the single-arg and Option-wrapped cases, so upgrades or new function shapes hit the unimplemented branch.","solutions":["Rewrite the function so each argument is wrapped in `Option<T>` (the macro's supported multi-arg path), e.g. `fn my_agg(a: Option<i64>, b: Option<i64>) -> i64` and handle None cases in the body.","Split the aggregate into a single-argument function, or pre-combine arguments before aggregation.","If support is genuinely needed, replace the `todo!()` in gen.rs with codegen that folds over multiple `#vN` inputs, and add a test."],"exampleFix":"// before - panics at macro expansion\n#[function(\"my_agg(int8, int8)\")]\nfn my_agg(a: i64, b: i64) -> i64 { a + b }\n\n// after - Option-wrapped args are supported\n#[function(\"my_agg(int8, int8)\")]\nfn my_agg(a: Option<i64>, b: Option<i64>) -> i64 {\n    match (a, b) { (Some(a), Some(b)) => a + b, _ => 0 }\n}","handlingStrategy":"validation","validationCode":"// Before declaring the aggregate, check the fn arity / Option-wrapping\nfn is_macro_compatible_agg(sig: &str) -> bool {\n    // only single-arg non-Option fns or Option-wrapped args are supported\n    let args = sig.split('(').nth(1).unwrap_or(\"\");\n    let argc = args.split(',').filter(|a| !a.trim().is_empty()).count();\n    argc == 1 || sig.contains(\"Option<\")\n}\nassert!(is_macro_compatible_agg(\"my_agg(int8, int8)\")); // panics here first, before cargo build","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer Option<T>-wrapped arguments for multi-argument aggregate functions — that is the macro's supported multi-arg path.","Search existing aggregate declarations in src/expr for the pattern you need and copy it.","Keep `todo!()` occurrences in gen.rs on your radar when bumping macro complexity; run `cargo check` on the crate early."],"tags":["proc-macro","compile-time","codegen","unimplemented"],"backgroundTag":"unsupported-operation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}