i_slint_compiler/passes/
lower_component_container.rs1use crate::diagnostics::BuildDiagnostics;
25use crate::langtype::ElementType;
26use crate::typeloader::TypeLoader;
27use crate::{expression_tree, object_tree::*};
28use std::cell::RefCell;
29use std::rc::Rc;
30
31pub fn lower_component_container(
32 doc: &Document,
33 type_loader: &mut TypeLoader,
34 diag: &mut BuildDiagnostics,
35) {
36 let empty_type = type_loader.global_type_registry.borrow().empty_type();
37
38 doc.visit_all_used_components(|component| {
39 recurse_elem_including_sub_components_no_borrow(component, &(), &mut |elem, _| {
40 if matches!(&elem.borrow().builtin_type(), Some(b) if b.name == "ComponentContainer") {
41 diagnose_component_container(elem, diag);
42 process_component_container(elem, &empty_type);
43 }
44 })
45 });
46}
47
48fn diagnose_component_container(element: &ElementRc, diag: &mut BuildDiagnostics) {
49 let elem = element.borrow();
50 if !elem.children.is_empty() {
51 diag.push_error("ComponentContainers may not have children".into(), &*element.borrow());
52 }
53 if let Some(cip) =
54 elem.enclosing_component.upgrade().unwrap().child_insertion_point.borrow().clone()
55 {
56 if Rc::ptr_eq(&cip.parent, element) {
57 diag.push_error(
58 "The @children placeholder cannot appear in a ComponentContainer".into(),
59 &*element.borrow(),
60 );
61 }
62 }
63}
64
65fn process_component_container(element: &ElementRc, empty_type: &ElementType) {
66 let suffix = element.borrow().id.clone();
67
68 let component = Rc::new_cyclic(|component_weak| {
69 let root_element = Rc::new(RefCell::new(Element {
70 id: smol_str::format_smolstr!("component_container_internal_{}", suffix),
71 base_type: empty_type.clone(),
72 enclosing_component: component_weak.clone(),
73 ..Default::default()
74 }));
75
76 Component {
77 node: element.borrow().debug.first().map(|n| n.node.clone().into()),
78 id: smol_str::format_smolstr!("ComponentContainerInternal_{}", suffix),
79 root_element,
80 ..Default::default()
81 }
82 });
83
84 let mut elem = element.borrow_mut();
85
86 let embedded_element = Element::make_rc(Element {
87 base_type: ElementType::Component(component.clone()),
88 id: smol_str::format_smolstr!("component_container_placeholder_{}", suffix),
89 debug: elem.debug.clone(),
90 enclosing_component: elem.enclosing_component.clone(),
91 default_fill_parent: (true, true),
92 inline_depth: elem.inline_depth,
93 repeated: Some(RepeatedElementInfo {
94 model: expression_tree::Expression::BoolLiteral(false),
95 model_data_id: Default::default(),
96 index_id: Default::default(),
97 is_conditional_element: true,
98 is_listview: None,
99 }),
100 is_component_placeholder: true,
101 ..Default::default()
102 });
103 elem.children.push(embedded_element);
104}