slint-ui/slint · error

there should be a popup menu if we want to show it

Error message

there should be a popup menu if we want to show it

What it means

When the C++ generator compiles the builtin `show-popup-menu` function, it expects `ctx.compilation_unit.popup_menu` to be `Some`. The compiler populates `popup_menu` exactly when a popup menu is used in the compilation unit, so a None here means the `show_popup_menu` builtin is being generated without the supporting popup-menu item tree having been registered.

Solutions

  1. Ensure the compilation pass that registers the popup menu item tree runs before C++ code generation
  2. Check that `compilation_unit.popup_menu` is populated whenever `show_popup_menu` appears in the expression set
  3. Replace the expect with a compile error diagnostic pointing at the missing popup menu declaration

Example fix

// before
let popup = ctx.compilation_unit.popup_menu.as_ref().expect("there should be a popup menu if we want to show it");
// after
let popup = ctx.compilation_unit.popup_menu.as_ref().unwrap_or_else(||
    panic!("show_popup_menu called but no popup menu was registered in this compilation unit"));
Defensive patterns

Strategy: validation

Validate before calling

if ctx.compilation_unit.popup_menu.is_none() {
    panic!("show_popup_menu generated but no popup menu registered in this compilation unit");
}

Type guard

let popup_menu = match ctx.compilation_unit.popup_menu.as_ref() {
    Some(p) => p,
    None => panic!("popup menu not registered; run the popup-menu collection pass first"),
};

Prevention

When it happens

Trigger: Compiling a call to `show-popup-menu` in a compilation unit where the `popup_menu` field was never set — e.g. the register_builtin_evaluation_functions/pass that collects the popup menu did not run or ran after codegen, or the popup menu declaration failed to register.

Common situations: Compiler development: changes to how `popup_menu` is collected on the CompilationUnit; partial compilation pipelines (LSP, live-preview) that skip the collection pass.

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@3a7e700487 (2026-09-16). Data as JSON: /api/errors/b360d110e31320f7. Report an issue: GitHub.

Appendix: source

Thrown at internal/compiler/generator/cpp.rs:5453

                component_access.then(|component_access| format!("{component_access}->{compo_path}globals->window().window_handle().close_popup({component_access}->{compo_path}popup_id_{popup_index})"))
            } else {
                panic!("internal error: invalid args to ClosePopupWindow {arguments:?}")
            }
        }

        BuiltinFunction::ShowPopupMenu | BuiltinFunction::ShowPopupMenuInternal => {
            let [llr::Expression::PropertyReference(context_menu_ref), entries, position] = arguments
            else {
                panic!("internal error: invalid args to ShowPopupMenu {arguments:?}")
            };

            let context_menu = access_member(context_menu_ref, ctx);
            let position = compile_expression(position, ctx);
            let popup = ctx
                .compilation_unit
                .popup_menu
                .as_ref()
                .expect("there should be a popup menu if we want to show it");
            let popup_id = ident(&ctx.compilation_unit.sub_components[popup.item_tree.root].name);
            let window = access_window_field(ctx);

            let popup_ctx = EvaluationContext::new_sub_component(
                ctx.compilation_unit,
                popup.item_tree.root,
                CppGeneratorContext { global_access: "self->globals".into(), conditional_includes: ctx.generator_state.conditional_includes },
                None,
            );
            let access_entries = access_member(&popup.entries, &popup_ctx).unwrap();
            let access_sub_menu = access_member(&popup.sub_menu, &popup_ctx).unwrap();
            let access_activated = access_member(&popup.activated, &popup_ctx).unwrap();
            let access_close = access_member(&popup.close, &popup_ctx).unwrap();

            item_owner(context_menu_ref).then_named("context_menu_owner", |owner| {
            let (_, context_menu_rc) = native_item_from_owner(context_menu_ref, ctx, owner);
            let close_popup = context_menu.then(|context_menu| {
                format!("{window}.close_popup({context_menu}.popup_id)")

View on GitHub (pinned to 3a7e700487)