Allow a borrowed key to move into children
The follwing code compiles did not compile in release mode before this PR but did in debug:
fn app(arg: String) -> Element {
rsx! {
div {
key: "{arg}",
for arg in Vec::from(arg) {}
}
}
}
This does not work in release as the macro only assembles the key at the end but the example moves the key into the children therefore not compiling. But in a debug build it works as the key is handled differently because of hot-reloading magic I guess.
I should probably include a test but I am not sure where as the rsx crate only includes macro parsing tests it seems.
RSX currently evaluates expressions in an odd order. Keys generally just borrow the contents of the expressions, but with dioxus' expanded version of formatted strings you can take a value inside of the expression. That can cause some expressions you would expect to be valid to fail to compile in this branch:
fn app(arg: String) -> Element {
rsx! {
div {
width: "{arg}", // I would expect this to run first and borrow arg
key: "{take(arg)}", // Then this to run and move arg
}
}
}
fn take<T>(t: T) -> T {
t
}
There is some overlap with https://github.com/DioxusLabs/dioxus/pull/3944 which switches to a more traditional evaluation order, but this PR fixes a case with keys #3944 doesn't handle.
Hm I see. Funnily enough your example compiles in release mode on main but not in debug builds because the take call is part of the __dynamic_literal_pool and arg is then later used in __dynamic_attributes but its already gone.
So I think in practice its very unlikely that people actually rely on this because if would only work in release builds. Also I think its not that common to have a key expression that takes ownership of a value to produce a key. I feel like my approach here still makes sense over all as it matches the debug build behavior better and from what I can tell does not really interfere with your PR?