slint-ui/slint · error

a setter belongs to a field

Error message

a setter belongs to a field

What it means

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.

Solutions

  1. Fix the pass that builds the `Property` so every setter is paired with a `field`
  2. Assert the setter/field pairing at Property construction time to fail earlier
  3. If you hit it as an end user, reduce the .slint input and file a bug with the reproduction

Example fix

// before
let setter = p.setter.as_ref().map(|setter| {
    let field = p.field.as_ref().expect("a setter belongs to a field");
// after
let setter = match (&p.setter, &p.field) {
    (Some(setter), Some(field)) => Some(/* emit setter using field */),
    (Some(_), None) => return Err(anyhow!("property {} has a setter but no field", p.name)),
    _ => None,
};
Defensive patterns

Strategy: validation

Validate before calling

debug_assert!(p.setter.is_none() || p.field.is_some(), "setter requires field");

Prevention

When it happens

Trigger: 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.

Common situations: Developers working on the compiler who add setter generation in a pass without allocating the backing field, or changing `Property` construction in llr lowering.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16). Data as JSON: /api/errors/f4a0ca69fe4fee0c. Report an issue: GitHub.

Appendix: source

Thrown at internal/compiler/generator/slint_sc.rs:440

                // A non-`Copy` field (a struct) is cloned on read.
                let read =
                    |field| if p.copy { quote!(self.#field) } else { quote!(self.#field.clone()) };
                let body = match &p.kind {
                    PropertyKind::Stored(_) => read(p.field.as_ref().unwrap()),
                    // A settable bound property falls back to the binding until
                    // set; a non-settable one always evaluates it.
                    PropertyKind::Binding(default) if p.setter.is_some() => {
                        let read = read(p.field.as_ref().unwrap());
                        // A block body: LLVM records no coverage for a closure
                        // whose body is a bare literal.
                        quote!(#read.unwrap_or_else(|| { #default }))
                    }
                    PropertyKind::Binding(default) => quote!(#default),
                };
                quote!(pub fn #getter(&self) -> #ty { #body })
            });
            let setter = p.setter.as_ref().map(|setter| {
                let field = p.field.as_ref().expect("a setter belongs to a field");
                let assign = match p.kind {
                    PropertyKind::Binding(_) => quote!(self.#field = Some(value);),
                    PropertyKind::Stored(_) => quote!(self.#field = value;),
                };
                quote!(pub fn #setter(&mut self, value: #ty) { #assign })
            });
            quote!(#getter #setter)
        });
        output.extend(quote! {
            /// The callbacks the component declares, which the application implements.
            pub trait #callbacks_trait {
                #(#trait_methods)*
            }

            #struct_decl
            impl #name {
                pub fn new(size: slint_sc::Size) -> Self {
                    #new_body

View on GitHub (pinned to bb937076de)