Compiler: properly transform property access from base expression in state

Fix #5038
This commit is contained in:
Olivier Goffart 2024-04-12 15:27:56 +02:00
parent aebc7570c8
commit 2c0ba2bc0f
2 changed files with 83 additions and 12 deletions

View file

@ -204,27 +204,28 @@ enum ExpressionForProperty {
fn expression_for_property(element: &ElementRc, name: &str) -> ExpressionForProperty {
let mut element_it = Some(element.clone());
let mut in_base = false;
while let Some(element) = element_it {
if let Some(e) = element.borrow().bindings.get(name) {
while let Some(elem) = element_it {
if let Some(e) = elem.borrow().bindings.get(name) {
let e = e.borrow();
if !e.two_way_bindings.is_empty() {
return ExpressionForProperty::TwoWayBinding;
}
if !matches!(e.expression, Expression::Invalid) {
let mut expr = e.expression.clone();
if !matches!(expr, Expression::Invalid) {
if in_base {
// Check that the expresison is valid in the new scope
let mut has_invalid = false;
e.expression.visit_recursive(&mut |ex| match ex {
expr.visit_recursive_mut(&mut |ex| match ex {
Expression::CallbackReference(nr, _)
| Expression::PropertyReference(nr)
| Expression::FunctionReference(nr, _) => {
let e = nr.element();
if !Rc::ptr_eq(&e, &element)
&& Weak::ptr_eq(
&e.borrow().enclosing_component,
&element.borrow().enclosing_component,
)
{
if Rc::ptr_eq(&e, &elem) {
*nr = NamedReference::new(element, nr.name());
} else if Weak::ptr_eq(
&e.borrow().enclosing_component,
&elem.borrow().enclosing_component,
) {
has_invalid = true;
}
}
@ -235,10 +236,10 @@ fn expression_for_property(element: &ElementRc, name: &str) -> ExpressionForProp
}
}
return ExpressionForProperty::Expression(e.expression.clone());
return ExpressionForProperty::Expression(expr);
}
}
element_it = if let ElementType::Component(base) = &element.borrow().base_type {
element_it = if let ElementType::Component(base) = &elem.borrow().base_type {
in_base = true;
Some(base.root_element.clone())
} else {

View file

@ -0,0 +1,70 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.1 OR LicenseRef-Slint-commercial
export global Glob {
in-out property <bool> cond2;
}
component Base inherits Rectangle {
in property <int> value;
}
export component R1 inherits Base {
t := TouchArea { }
ti := TextInput { text: Glob.cond2 ? "a" : "b"; }
states [
xxx when ti.text == "a" : {
value: 1;
}
hover when t.has-hover: {
background: white;
value: 2;
}
]
}
export component R2 inherits R1 { }
export component TestCase inherits Window {
in property <bool> cond1;
r2 := R2 {
states [
s1 when cond1: {
background: white;
value: 3;
}
]
}
out property <int> value: r2.value;
}
/*
```cpp
auto handle = TestCase::create();
const TestCase &instance = *handle;
assert_eq(instance.get_value(), 0);
instance.global<Glob>().set_cond2(true);
assert_eq(instance.get_value(), 1);
instance.set_cond1(true);
assert_eq(instance.get_value(), 3);
```
```rust
let instance = TestCase::new().unwrap();
assert_eq!(instance.get_value(), 0);
instance.global::<Glob<'_>>().set_cond2(true);
assert_eq!(instance.get_value(), 1);
instance.set_cond1(true);
assert_eq!(instance.get_value(), 3);
```
*/