{"record":{"id":"f4a0ca69fe4fee0c","repo":"slint-ui/slint","slug":"a-setter-belongs-to-a-field","errorCode":null,"errorMessage":"a setter belongs to a field","messagePattern":"a setter belongs to a field","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/compiler/generator/slint_sc.rs","lineNumber":440,"sourceCode":"                // A non-`Copy` field (a struct) is cloned on read.\n                let read =\n                    |field| if p.copy { quote!(self.#field) } else { quote!(self.#field.clone()) };\n                let body = match &p.kind {\n                    PropertyKind::Stored(_) => read(p.field.as_ref().unwrap()),\n                    // A settable bound property falls back to the binding until\n                    // set; a non-settable one always evaluates it.\n                    PropertyKind::Binding(default) if p.setter.is_some() => {\n                        let read = read(p.field.as_ref().unwrap());\n                        // A block body: LLVM records no coverage for a closure\n                        // whose body is a bare literal.\n                        quote!(#read.unwrap_or_else(|| { #default }))\n                    }\n                    PropertyKind::Binding(default) => quote!(#default),\n                };\n                quote!(pub fn #getter(&self) -> #ty { #body })\n            });\n            let setter = p.setter.as_ref().map(|setter| {\n                let field = p.field.as_ref().expect(\"a setter belongs to a field\");\n                let assign = match p.kind {\n                    PropertyKind::Binding(_) => quote!(self.#field = Some(value);),\n                    PropertyKind::Stored(_) => quote!(self.#field = value;),\n                };\n                quote!(pub fn #setter(&mut self, value: #ty) { #assign })\n            });\n            quote!(#getter #setter)\n        });\n        output.extend(quote! {\n            /// The callbacks the component declares, which the application implements.\n            pub trait #callbacks_trait {\n                #(#trait_methods)*\n            }\n\n            #struct_decl\n            impl #name {\n                pub fn new(size: slint_sc::Size) -> Self {\n                    #new_body","sourceCodeStart":422,"sourceCodeEnd":458,"githubUrl":"https://github.com/slint-ui/slint/blob/bb937076de3f7919766c1f25e2e969367cf77e9a/internal/compiler/generator/slint_sc.rs#L422-L458","documentation":"In the slint_sc (safety-critical) generator, codegen for a property distinguishes stored properties (which read a struct field) from binding-kind properties (which evaluate a binding). The unwrap of p.field asserts the invariant that any property reaching the Stored arm has an backing field — i.e. 'a setter belongs to a field'. The panic fires when a property is marked stored/settable but the lowering pass failed to assign it a field, indicating an internal inconsistency between the property analysis and the generator.","triggerScenarios":"A pass (e.g. default_geometry or the SC lowering) produced a `Property` with `setter: Some(_)` but `field: None`. This is a compiler-internal bug, not user code.","commonSituations":"Developers working on the compiler who add setter generation in a pass without allocating the backing field, or changing `Property` construction in llr lowering.","solutions":["Fix the pass that builds the `Property` so every setter is paired with a `field`","Assert the setter/field pairing at Property construction time to fail earlier","If you hit it as an end user, reduce the .slint input and file a bug with the reproduction"],"exampleFix":"// before\nlet setter = p.setter.as_ref().map(|setter| {\n    let field = p.field.as_ref().expect(\"a setter belongs to a field\");\n// after\nlet setter = match (&p.setter, &p.field) {\n    (Some(setter), Some(field)) => Some(/* emit setter using field */),\n    (Some(_), None) => return Err(anyhow!(\"property {} has a setter but no field\", p.name)),\n    _ => None,\n};","handlingStrategy":"validation","validationCode":"debug_assert!(p.setter.is_none() || p.field.is_some(), \"setter requires field\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When constructing generator Properties, always allocate the field before the setter","Add construction-time asserts so violations surface at the pass, not at codegen"],"tags":["rust","compiler","panic","codegen"],"backgroundTag":"internal-invariant-violation","analyzedSha":"bb937076de3f7919766c1f25e2e969367cf77e9a","analyzedAt":"2026-09-16T01:37:20.251Z","contentChangedAt":"2026-09-16T01:37:20.251Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}