{"record":{"id":"133f9e4174b6a4e3","repo":"risingwavelabs/risingwave","slug":"expect-accumulate-function","errorCode":null,"errorMessage":"expect accumulate function","messagePattern":"expect accumulate function","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/expr/macro/src/parse.rs","lineNumber":157,"sourceCode":"impl Parse for AggregateImpl {\n    fn parse(input: ParseStream<'_>) -> Result<Self> {\n        let itemimpl: syn::ItemImpl = input.parse()?;\n        let parse_function = |name: &str| {\n            itemimpl.items.iter().find_map(|item| match item {\n                syn::ImplItem::Fn(syn::ImplItemFn { sig, .. }) if sig.ident == name => {\n                    Some(UserFunctionAttr::from(sig))\n                }\n                _ => None,\n            })\n        };\n        let self_path = itemimpl.self_ty.to_token_stream().to_string();\n        let struct_name = match self_path.split_once('<') {\n            Some((path, _)) => path.trim().into(), // remove generic parameters\n            None => self_path,\n        };\n        Ok(AggregateImpl {\n            struct_name,\n            accumulate: parse_function(\"accumulate\").expect(\"expect accumulate function\"),\n            retract: parse_function(\"retract\"),\n            merge: parse_function(\"merge\"),\n            finalize: parse_function(\"finalize\"),\n            create_state: parse_function(\"create_state\"),\n            encode_state: parse_function(\"encode_state\"),\n            decode_state: parse_function(\"decode_state\"),\n        })\n    }\n}\n\nimpl Parse for AggregateFnOrImpl {\n    fn parse(input: ParseStream<'_>) -> Result<Self> {\n        // consume attributes\n        let _ = input.call(syn::Attribute::parse_outer)?;\n        if input.peek(Token![impl]) {\n            Ok(AggregateFnOrImpl::Impl(input.parse()?))\n        } else {\n            Ok(AggregateFnOrImpl::Fn(input.parse()?))","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/macro/src/parse.rs#L139-L175","documentation":"Parsing an `#[aggregate]` `impl` block requires an `accumulate` method — it is the mandatory core of the aggregate state machine (retract/merge/finalize etc. are optional). `AggregateImpl::parse` uses `.expect(\"expect accumulate function\")` and panics during macro expansion if no method named `accumulate` exists in the impl.","triggerScenarios":"Writing `#[aggregate]` on an `impl MyState { fn retract(...) ... }` block that lacks `fn accumulate(...)`; misspelling it (`accmulate`, `acc`) or defining it as an associated function of another impl block.","commonSituations":"New contributor scaffolding a custom aggregate from an example that only showed optional methods; renaming `accumulate` during refactors; splitting methods across multiple impl blocks so the macro's single-item-impl scan misses it.","solutions":["Add `fn accumulate(&mut self, state: &mut ..., arg0: ..., ...) -> ...` inside the same impl block the `#[aggregate]` attribute is applied to.","Fix the method's spelling to exactly `accumulate`.","Ensure all aggregate methods (accumulate plus any retract/merge/finalize) live in the single `impl` block annotated with `#[aggregate]`."],"exampleFix":"// before - no accumulate method\n#[aggregate]\nimpl SumState {\n    fn create_state() -> Self { Self { sum: 0 } }\n}\n\n// after\n#[aggregate]\nimpl SumState {\n    fn create_state() -> Self { Self { sum: 0 } }\n    fn accumulate(&mut self, v: Option<i64>) { self.sum += v.unwrap_or(0); }\n}","handlingStrategy":"validation","validationCode":"// Structurally: an #[aggregate] impl block must contain `fn accumulate`\nfn has_accumulate(impl_src: &str) -> bool {\n    impl_src.contains(\"fn accumulate(\")\n}\nassert!(has_accumulate(\"impl S { fn accumulate(&mut self, v: i64) {} }\"));","typeGuard":null,"tryCatchPattern":"// Compile-time panic; guard with a trybuild test:\n// #[test] fn aggregate_requires_accumulate() {\n//     trybuild::TestCases::new().compile_fail(\"tests/ui/aggregate_without_accumulate.rs\");\n// }","preventionTips":["Always implement `accumulate` first when writing a custom aggregate; add retract/merge/finalize afterwards.","Keep all aggregate methods in the single impl block annotated with #[aggregate].","Copy the skeleton from an existing aggregate impl (e.g. src/expr/*/sum.rs style examples)."],"tags":["proc-macro","compile-time","aggregate","missing-method"],"backgroundTag":"missing-required-argument","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}