Panic when accessing properties of the parent and the parent was deleted.
Update
The original bug was fixed for Rust and C++, but not yet for the interpreter.
When this bug is fixed, we can remove this line
https://github.com/slint-ui/slint/blob/bf4ab9a01466c5523a988aa622899d99726794c7/tests/cases/models/delete_from_clicked.slint#L62-L63
And this line
https://github.com/slint-ui/slint/blob/bf4ab9a01466c5523a988aa622899d99726794c7/tests/driver/rust/build.rs#L30-L31
Another candidate testcase is in this comment: https://github.com/slint-ui/slint/issues/4699#issuecomment-1983295178
Bug report
Imagine this code:
component Foo {
// connecte in native code to something that remove item from the model
callback clicked(int);
in property <[string]> model;
for string[idx] in model: abcd := Rectangle {
property <int> foo: idx;
// This create a new repeated component with a parent
if true : efgh := Button {
clicked => {
// native code will remove element from the model that will destroy the repeated component `abcd`
root.clicked(idx);
// accessing `foo` in the parent will cause panic in rust or UB (crash) in C++
debug(foo);
}
}
}
To reproduce this, edit the test delete_from_clicked.slint to uncomment the commented line:
https://github.com/slint-ui/slint/blob/f546d22861af3199b801c77185b59b2a52906c3d/tests/cases/models/delete_from_clicked.slint#L39
Ideally this test should work with only the line 39 commented, and the line 37 removed (so asign the value only after the clicked handler)
The problem is that ItemRc keeps the item and its enclosing ItemTree alive. but the ItemTree's parent is a weak and is destroyed, so we unwrap the parent.upgrade().unwrap() in the generated binding https://github.com/slint-ui/slint/blob/5bf2c7192b6264947e5e80e7e85f831f4ea3f852/internal/compiler/generator/rust.rs#L1726 (and other places)
How to fix?
Option 1
Make ItemRc keep all the parent ItemTree alive. In otder to do so without introducing cycle, ItemRc could have a Vec<ItemTreeRc> instead of a simple ItemTreeRc. But that could be quite expensive. ItemRc could also call increment_strong_count manually on all the parent. and decrement_strong_count when Drop'ed
Option 2
Make the property binding failable and use ? or early return when something goes wrong. So instead of unwrapping the parent, we just check it and fail the binding if there is an error.
The problem is what happen to the value of a binding that errors out? Default value? Previous value? Poisoned value? Stay dirty? Do error buble up to all dependent properties?
Option 3
When accessing the property of a deleted parent, just map_or_default instead of unwrap. So we get the default propery instead. Getting the default value is probably wrong behavior though. Especially if the binding/callback has side effect.
The bug was fixed for rust in #5813 , but the bug remains in C++ and in the interpreter
Sorry, that got closed by accident.
C++ part was done in https://github.com/slint-ui/slint/pull/9863