{"record":{"id":"4e2ef351aa749ebb","repo":"risingwavelabs/risingwave","slug":"expect-fn","errorCode":null,"errorMessage":"expect fn","messagePattern":"expect fn","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/macro/src/lib.rs","lineNumber":599,"sourceCode":"    encode_state: Option<UserFunctionAttr>,\n    #[allow(dead_code)] // TODO(wrj): support decode\n    decode_state: Option<UserFunctionAttr>,\n}\n\n#[derive(Debug, Clone)]\n#[allow(clippy::large_enum_variant)]\nenum AggregateFnOrImpl {\n    /// A simple accumulate/retract function.\n    Fn(UserFunctionAttr),\n    /// A full impl block.\n    Impl(AggregateImpl),\n}\n\nimpl AggregateFnOrImpl {\n    fn as_fn(&self) -> &UserFunctionAttr {\n        match self {\n            AggregateFnOrImpl::Fn(attr) => attr,\n            _ => panic!(\"expect fn\"),\n        }\n    }\n\n    fn accumulate(&self) -> &UserFunctionAttr {\n        match self {\n            AggregateFnOrImpl::Fn(attr) => attr,\n            AggregateFnOrImpl::Impl(impl_) => &impl_.accumulate,\n        }\n    }\n\n    fn has_retract(&self) -> bool {\n        match self {\n            AggregateFnOrImpl::Fn(fn_) => fn_.retract,\n            AggregateFnOrImpl::Impl(impl_) => impl_.retract.is_some(),\n        }\n    }\n}\n","sourceCodeStart":581,"sourceCodeEnd":617,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/macro/src/lib.rs#L581-L617","documentation":"`AggregateFnOrImpl::as_fn` in src/expr/macro/src/lib.rs unwraps the enum to the `Fn` variant; any other variant (an `impl`-based aggregate) hits `panic!(\"expect fn\")`. The macro internally assumed it was dealing with a plain function attribute but was handed an aggregate `impl` block instead.","triggerScenarios":"Calling `as_fn()` on an `AggregateFnOrImpl::Impl` value — i.e. code paths in the macro that expect a function-style `#[aggregate(...)]` declaration receive an `impl ... for ...` aggregate definition, such as when a non-aggregate macro path processes an impl block.","commonSituations":"Macro-internal misuse when adding new aggregate features; a developer routes an `impl`-based aggregate (with `accumulate`/`retract` methods) through an API that only supports single-function aggregates.","solutions":["Use the impl-based code path (e.g. `accumulate()` or matching on the enum) instead of `as_fn()` when the value may be an `Impl` variant.","Declare the aggregate as a single function rather than an impl block if the calling macro only supports fn-form aggregates.","In macro code, replace the panic with a proper `abort!`/compile error explaining that impl-based aggregates are unsupported here."],"exampleFix":"// before - panics for Impl variants\nlet attr = agg.as_fn();\n\n// after - handle both variants\nlet attr = match agg {\n    AggregateFnOrImpl::Fn(attr) => attr,\n    AggregateFnOrImpl::Impl(imp) => &imp.accumulate,\n};","handlingStrategy":"type-guard","validationCode":"// In macro code, never unwrap blindly:\nfn ensure_fn(v: &AggregateFnOrImpl) -> Option<&UserFunctionAttr> {\n    match v { AggregateFnOrImpl::Fn(a) => Some(a), _ => None }\n}","typeGuard":"fn as_fn_safe(v: &AggregateFnOrImpl) -> Option<&UserFunctionAttr> {\n    if let AggregateFnOrImpl::Fn(attr) = v { Some(attr) } else { None }\n}","tryCatchPattern":"// This panics at compile time of the downstream crate; catch it by testing macro expansion:\n// trybuild-style test\n// #[test] fn reject_impl_in_fn_path() { let t = trybuild::TestCases::new(); t.compile_fail(\"tests/ui/impl_in_fn_path.rs\"); }","preventionTips":["Match on AggregateFnOrImpl explicitly instead of calling as_fn() in new code paths.","Add a trybuild compile-fail test covering the mismatch case.","Convert internal panics to proc_macro_error::abort! for better diagnostics."],"tags":["proc-macro","compile-time","panic","invariant"],"backgroundTag":"invalid-argument-value","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}