slint-ui / slint

Slint is a declarative GUI toolkit to build native user interfaces for Rust, C++, or JavaScript apps.
https://slint.dev
Other
15.9k stars 519 forks source link

Interpreter panics if animation properties depends on model #5500

Closed danutsu closed 3 days ago

danutsu commented 3 days ago

On Slintpad, paste the following code:

import { AboutSlint, Button, VerticalBox, ListView, Spinner } from "std-widgets.slint";

struct Data {
    t: string,
    dur: duration,
}

export component Demo {
    height: 300px;
    width: 600px;
    property <[Data]> data: [
        { t: "one", dur: 8s }, { t: "two", dur: 5s }];

    ListView { 
        for d in data: HorizontalLayout {
            Text {
                text: d.t;
            }
            Spinner {
                progress: 0.0;
                init() => {
                    self.progress = 1.0;
                }
                animate progress {
                    duration: d.dur;
                }
            }
        }
    }
}

Expected: works fine and one animated spinner is displayed. Actual: preview UI freezes with "Updating preview..." and console is full of errors like:

Uncaught RuntimeError: unreachable executed
    x3e https://slintpad.com/assets/index-BciMDBKc.js:1443
    s https://slintpad.com/assets/index-BciMDBKc.js:1443
[slint_lsp_wasm_bg-DCRs-Vjn.wasm:4258030:1](https://slintpad.com/assets/slint_lsp_wasm_bg-DCRs-Vjn.wasm)
Uncaught (in promise) Error: Unknown parameter structure byName
    Ro https://slintpad.com/assets/index-BciMDBKc.js:1390
    we https://slintpad.com/assets/index-BciMDBKc.js:1390
    sendRequest https://slintpad.com/assets/index-BciMDBKc.js:1390

It has something to do with the binding: if you replace d.dur in the duration line with 1s it previews fine.

danutsu commented 3 days ago

As a note: building/running the above code locally, in Rust, works fine, so it seems to be a slintpad issue.

ogoffart commented 3 days ago

Thanks for filling a bug. This can be reproduced with the Slint viewer.

thread 'main' panicked at internal/interpreter/eval.rs:1541:49:
called `Result::unwrap()` on an `Err` value: ()
...
   4: slint_interpreter::eval::new_struct_with_bindings
             at ./internal/interpreter/eval.rs:1541:13
   5: slint_interpreter::dynamic_item_tree::animation_for_property
             at ./internal/interpreter/dynamic_item_tree.rs:1236:44
   6: slint_interpreter::dynamic_item_tree::instantiate::{{closure}}
             at ./internal/interpreter/dynamic_item_tree.rs:1473:39
   7: i_slint_compiler::generator::handle_property_bindings_init::handle_property_inner
             at ./internal/compiler/generator.rs:433:9
ogoffart commented 3 days ago

Even more reduced testcase:

export component Demo {
    for d in [8s]: TouchArea {
        property <float> progress: 0.0;
        function set() {
            progress = 1
        }
        animate progress { duration: d; }
    }
}
ogoffart commented 3 days ago

I investigated the issue. The problem is that the bindings for animated property are read when the itemtree is instentiated. (Because of issue #348) And in this case, we are reading the model data before it's been set in the update call, so it still has a value of Value::Void and we panic as that's not the correct type for a duration.