i_slint_compiler/object_tree/
forward_inherited_expression.rs1use super::{BindingExpression, ElementRc, ElementType, PropertyDeclaration};
5use crate::expression_tree::{Callable, Expression};
6use crate::langtype::Type;
7use crate::namedreference::NamedReference;
8use crate::symbol_counters::SymbolCounters;
9use std::collections::HashMap;
10use std::rc::{Rc, Weak};
11
12#[derive(Default)]
13pub(crate) struct ForwardedReferenceCache {
14 forwarded_references: HashMap<NamedReference, NamedReference>,
15}
16
17pub(crate) enum InheritedExpression {
18 Expression(Expression),
19 TwoWayBinding,
20 Unbound,
21}
22
23pub(crate) fn forward_inherited_expression(
24 element: &ElementRc,
25 property_name: &str,
26 symbol_counters: &SymbolCounters,
27 forwarded_references: &mut ForwardedReferenceCache,
28) -> InheritedExpression {
29 let ElementType::Component(base_component) = &element.borrow().base_type else {
30 return InheritedExpression::Unbound;
31 };
32 let mut current_base_root = base_component.root_element.clone();
33
34 loop {
35 let binding = current_base_root
36 .borrow()
37 .binding(property_name)
38 .map(|binding| (!binding.two_way_bindings.is_empty(), binding.expression.clone()));
39 if let Some((is_two_way_binding, mut expression)) = binding {
40 if is_two_way_binding {
41 return InheritedExpression::TwoWayBinding;
42 }
43 if !matches!(expression, Expression::Invalid) {
44 rebase_expression_to_instance(
45 &mut expression,
46 ¤t_base_root,
47 element,
48 symbol_counters,
49 forwarded_references,
50 );
51 return InheritedExpression::Expression(expression);
52 }
53 }
54
55 let next_source_root = {
56 let source_root = current_base_root.borrow();
57 let ElementType::Component(base_component) = &source_root.base_type else {
58 return InheritedExpression::Unbound;
59 };
60 base_component.root_element.clone()
61 };
62 current_base_root = next_source_root;
63 }
64}
65
66fn rebase_expression_to_instance(
67 expression: &mut Expression,
68 base_root_element: &ElementRc,
69 target_instance: &ElementRc,
70 symbol_counters: &SymbolCounters,
71 forwarded_references: &mut ForwardedReferenceCache,
72) {
73 expression.visit_recursive_mut(&mut |expression| match expression {
74 Expression::PropertyReference(named_reference)
75 | Expression::FunctionCall {
76 function: Callable::Callback(named_reference) | Callable::Function(named_reference),
77 ..
78 } => {
79 let referenced_element = named_reference.element();
80 if Rc::ptr_eq(&referenced_element, base_root_element) {
81 *named_reference =
82 NamedReference::new(target_instance, named_reference.name().clone());
83 } else if Weak::ptr_eq(
84 &referenced_element.borrow().enclosing_component,
85 &base_root_element.borrow().enclosing_component,
86 ) {
87 let forwarded_reference = forward_reference(
88 named_reference,
89 base_root_element,
90 symbol_counters,
91 forwarded_references,
92 );
93 *named_reference =
94 NamedReference::new(target_instance, forwarded_reference.name().clone());
95 }
96 }
97 _ => (),
98 });
99}
100
101fn forward_reference(
102 original: &NamedReference,
103 base_root: &ElementRc,
104 symbol_counters: &SymbolCounters,
105 forwarded_references: &mut ForwardedReferenceCache,
106) -> NamedReference {
107 if let Some(existing) = forwarded_references.forwarded_references.get(original) {
108 return existing.clone();
109 }
110
111 let property_type = original.ty();
112 let property_name = symbol_counters.generate_name("forward_reference_");
113 let binding = match &property_type {
114 Type::Callback(function) | Type::Function(function) => {
115 let arguments = function
116 .args
117 .iter()
118 .enumerate()
119 .map(|(index, argument_type)| Expression::FunctionParameterReference {
120 index,
121 ty: argument_type.clone(),
122 })
123 .collect();
124 let function = if matches!(property_type, Type::Callback(_)) {
125 Callable::Callback(original.clone())
126 } else {
127 Callable::Function(original.clone())
128 };
129 Expression::FunctionCall { function, arguments, source_location: None }
130 }
131 _ => Expression::PropertyReference(original.clone()),
132 };
133
134 base_root.borrow_mut().property_declarations.insert(
135 property_name.clone(),
136 PropertyDeclaration { property_type, ..PropertyDeclaration::default() },
137 );
138 base_root.borrow_mut().set_binding(property_name.clone(), BindingExpression::from(binding));
139
140 let forwarded_reference = NamedReference::new(base_root, property_name);
141 forwarded_references.forwarded_references.insert(original.clone(), forwarded_reference.clone());
142 forwarded_reference
143}