DioxusLabs / dioxus

Fullstack GUI library for web, desktop, mobile, and more.
https://dioxuslabs.com
Apache License 2.0
19.3k stars 735 forks source link

Rsx panics on an empty conditional block #2270

Closed rogusdev closed 2 months ago

rogusdev commented 2 months ago

Problem

This fails with a panic:

#[component]
fn Home() -> Element {
    rsx! {
        if true {
        }
    }
}

But this works:

#[component]
fn Home() -> Element {
    rsx! {
    }
}

The failure case was extra confusing to me because I was using if signal() {...} -- where the insides of those braces was empty while I was developing / debugging the signal itself. So I kept thinking I had done something wrong with the signal, rather than simply having an empty block after an rsx conditional.

Steps To Reproduce

Steps to reproduce the behavior:

It is trivial to recreate this, just dx new and change the Home Element as above.

dx new
✔ 🤷   Which sub-template should be expanded? · Web
🤷   Project Name: empty-conditional
✔ 🤷   How do you want to create CSS? · Vanilla
✔ 🤷   Should the application use the Dioxus router? · true

nano src/main.rs
dx serve

Expected behavior

Do not panic in the browser.

Screenshots

The panic message was:

panicked at /home/chris/.cargo/registry/src/index.crates.io-6f17d22bba15001f/dioxus-core-0.5.1/src/diff/node.rs:642:16:
index out of bounds: the len is 0 but the index is 0

Stack:
[very long stack]

Environment:

Questionnaire

ealmloff commented 2 months ago

I cannot reproduce this issue on MacOs with this code: https://github.com/ealmloff/fail-reproduce-2270

rogusdev commented 2 months ago

Hmm, I can reproduce it every time in my win11 WSL ubuntu, but I don't have a mac to test on.

chris@rzr-bl16-2023 ~/git> dx new
✔ 🤷   Which sub-template should be expanded? · Web
🤷   Project Name: rsx-empty-conditional
✔ 🤷   How do you want to create CSS? · Vanilla
✔ 🤷   Should the application use the Dioxus router? · true
chris@rzr-bl16-2023 ~/git> nano rsx-empty-conditional/src/main.rs
chris@rzr-bl16-2023 ~/git> cd rsx-empty-conditional/
chris@rzr-bl16-2023 ~/g/rsx-empty-conditional (main)> cat src/main.rs
...

#[component]
fn Home() -> Element {
    rsx! {
        if true {
        }
    }
}

chris@rzr-bl16-2023 ~/g/rsx-empty-conditional (main)> dx serve

http://localhost:8080/

Screenshot 2024-04-08 083821

Screenshot 2024-04-08 084245

(Browser screenshot edited to hide my links and extensions)

rogusdev commented 2 months ago

Oh and to be clear: your fail-repro repo does NOT panic for me either. So something is clearly different in the way that was setup.

rogusdev commented 2 months ago

I generated mine with

dx --version
dioxus 0.5.4

Did you do the same? Because I do see slight differences in the dist output:

diff -r ./dist/ ../fail-reproduce-2270/dist/
Only in ./dist/assets/dioxus: rsx-empty-conditional.js
Only in ./dist/assets/dioxus: rsx-empty-conditional_bg.wasm
diff '--color=auto' -r ./dist/assets/dioxus/snippets/dioxus-interpreter-js-7c1300c6684e1811/inline0.js ../fail-reproduce-2270/dist/assets/dioxus/snippets/dioxus-interpreter-js-7c1300c6684e1811/inline0.js
4c4
<             let ns,value,id,many,bubbles,field;
---
>             let value,many,bubbles,field,id,ns;
17,25c17,25
<                     this.u32buf=null;this.u32bufp=null;this.evt = [];
<                     this.evt_cache_hit = null;
<                     this.evt_cache_idx;
<                     this.get_evt = function() {
<                         this.evt_cache_idx = this.u8buf[this.u8bufp++];
<                         if(this.evt_cache_idx & 128){
<                             this.evt_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]);
<                             this.evt[this.evt_cache_idx&4294967167]=this.evt_cache_hit;
<                             return this.evt_cache_hit;
---
>                     this.namespace = [];
>                     this.namespace_cache_hit = null;
>                     this.namespace_cache_idx;
>                     this.get_namespace = function() {
>                         this.namespace_cache_idx = this.u8buf[this.u8bufp++];
>                         if(this.namespace_cache_idx & 128){
>                             this.namespace_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]);
>                             this.namespace[this.namespace_cache_idx&4294967167]=this.namespace_cache_hit;
>                             return this.namespace_cache_hit;
28c28
<                             return this.evt[this.evt_cache_idx&4294967167];
---
>                             return this.namespace[this.namespace_cache_idx&4294967167];
43c43
<                     };this.u8buf=null;this.u8bufp=null;this.el = [];
---
>                     };this.el = [];
69,77c69,77
<                     };this.namespace = [];
<                     this.namespace_cache_hit = null;
<                     this.namespace_cache_idx;
<                     this.get_namespace = function() {
<                         this.namespace_cache_idx = this.u8buf[this.u8bufp++];
<                         if(this.namespace_cache_idx & 128){
<                             this.namespace_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]);
<                             this.namespace[this.namespace_cache_idx&4294967167]=this.namespace_cache_hit;
<                             return this.namespace_cache_hit;
---
>                     };this.u32buf=null;this.u32bufp=null;this.u16buf=null;this.u16bufp=null;this.s = "";this.lsp = null;this.sp = null;this.sl = null;this.c = new TextDecoder();this.evt = [];
>                     this.evt_cache_hit = null;
>                     this.evt_cache_idx;
>                     this.get_evt = function() {
>                         this.evt_cache_idx = this.u8buf[this.u8bufp++];
>                         if(this.evt_cache_idx & 128){
>                             this.evt_cache_hit=this.s.substring(this.sp,this.sp+=this.u8buf[this.u8bufp++]);
>                             this.evt[this.evt_cache_idx&4294967167]=this.evt_cache_hit;
>                             return this.evt_cache_hit;
80c80
<                             return this.namespace[this.namespace_cache_idx&4294967167];
---
>                             return this.evt[this.evt_cache_idx&4294967167];
82c82
<                     };this.u16buf=null;this.u16bufp=null;this.s = "";this.lsp = null;this.sp = null;this.sl = null;this.c = new TextDecoder();
---
>                     };this.u8buf=null;this.u8bufp=null;
99,103c99
<             this.u32bufp=0;if ((this.metaflags>>>5)&1){
<                 this.t = this.m.getUint32(this.d+5*4,true);
<                 this.u8buf=new Uint8Array(this.m.buffer,this.t,((this.m.buffer.byteLength-this.t)-(this.m.buffer.byteLength-this.t)%1)/1);
<             }
<             this.u8bufp=0;if ((this.metaflags>>>4)&1){
---
>             this.u32bufp=0;if ((this.metaflags>>>4)&1){
133c129,133
<             this.sp=0;
---
>             this.sp=0;if ((this.metaflags>>>5)&1){
>                 this.t = this.m.getUint32(this.d+5*4,true);
>                 this.u8buf=new Uint8Array(this.m.buffer,this.t,((this.m.buffer.byteLength-this.t)-(this.m.buffer.byteLength-this.t)%1)/1);
>             }
>             this.u8bufp=0;
rogusdev commented 2 months ago

So, I reproduced this locally many times, then I pushed one of them up: https://github.com/rogusdev/rsx-empty-conditional and when I cloned that one back down, it did not fail -- the first time. The second and subsequent times it all failed. So I tried yours again... and it fails every time now. Idk what is going on. But perhaps try dx serve with yours a second time after cloning, or try mine twice, and see what happens. Nor do I know why this would happen only after the first run after cloning, but always on the first try with a new scaffold from dx serve.

ealmloff commented 2 months ago

My cargo.lock was out of date. I can reproduce this with dioxus 0.5.1