>) -> Element;
/// ```
- pub fn component(
+ pub fn component<'child, P>(
&'src self,
- component: fn(Scope<'src, P>) -> Element<'src>,
+ component: fn(Scope<'child, P>) -> Element<'child>,
props: P,
fn_name: &'static str,
) -> DynamicNode<'src>
where
- P: Properties + 'src,
+ P: Properties + 'child,
+ 'src: 'child,
{
let vcomp = VProps::new(component, P::memoize, props);
// cast off the lifetime of the render return
- let as_dyn: Box + '_> = Box::new(vcomp);
+ let as_dyn: Box + '_> = Box::new(vcomp);
let extended: Box + 'src> = unsafe { std::mem::transmute(as_dyn) };
DynamicNode::Component(VComponent {
From 91500f0349044a1895f8da809f98d2366fd8f0aa Mon Sep 17 00:00:00 2001
From: Evan Almloff
Date: Wed, 9 Aug 2023 10:29:19 -0700
Subject: [PATCH 6/9] add props safety example
---
examples/props_safety.rs | 68 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 examples/props_safety.rs
diff --git a/examples/props_safety.rs b/examples/props_safety.rs
new file mode 100644
index 000000000..7802e75c9
--- /dev/null
+++ b/examples/props_safety.rs
@@ -0,0 +1,68 @@
+use dioxus::prelude::*;
+
+fn main() {
+ dioxus_desktop::launch(app);
+}
+
+fn app(cx: Scope) -> Element {
+ let count: &RefCell> = cx.use_hook(|| RefCell::new(Vec::new()));
+
+ let element = render! {
+ div {
+ "hello world!"
+ }
+ };
+
+ let nested_borrows = cx.use_hook(Vec::new);
+ nested_borrows.push("hello world!");
+
+ cx.render(rsx! {
+ // unsafe_child_component {
+ // borrowed: count
+ // }
+ safe_child_component {
+ borrowed: element
+ }
+ safe_nested_borrows {
+ borrowed: &**nested_borrows
+ }
+ })
+}
+
+#[derive(Props)]
+struct NestedBorrows<'a> {
+ borrowed: &'a [&'a str],
+}
+
+fn safe_nested_borrows<'a>(cx: Scope<'a, NestedBorrows<'a>>) -> Element<'a> {
+ render! {
+ div { "{cx.props.borrowed:?}" }
+ }
+}
+
+#[derive(Props)]
+struct Testing<'a> {
+ borrowed: &'a RefCell>>,
+}
+
+fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> {
+ let Testing { borrowed } = cx.props;
+ let borrowed = borrowed.borrow();
+ cx.render(rsx! {
+ div { "Hello, world!" }
+ })
+}
+
+#[derive(Props)]
+struct SafeTesting<'a> {
+ borrowed: Element<'a>,
+}
+
+fn safe_child_component<'a>(cx: Scope<'a, SafeTesting<'a>>) -> Element<'a> {
+ let SafeTesting { borrowed } = cx.props;
+ cx.render(rsx! {
+ div {
+ borrowed
+ }
+ })
+}
From f91eeccca784ea2c64c751148d052f513b2c77d2 Mon Sep 17 00:00:00 2001
From: Evan Almloff
Date: Wed, 9 Aug 2023 10:49:47 -0700
Subject: [PATCH 7/9] add compile test for unsound case
---
packages/core/Cargo.toml | 1 +
packages/core/compile_tests/props_safety.rs | 32 +++++++++++++++++++
.../core/compile_tests/props_safety.stderr | 20 ++++++++++++
packages/core/src/properties.rs | 6 ++++
4 files changed, 59 insertions(+)
create mode 100644 packages/core/compile_tests/props_safety.rs
create mode 100644 packages/core/compile_tests/props_safety.stderr
diff --git a/packages/core/Cargo.toml b/packages/core/Cargo.toml
index 7c9515fc0..71afe5825 100644
--- a/packages/core/Cargo.toml
+++ b/packages/core/Cargo.toml
@@ -39,6 +39,7 @@ dioxus = { workspace = true }
pretty_assertions = "1.3.0"
rand = "0.8.5"
dioxus-ssr = { workspace = true }
+trybuild = "1.0"
[features]
default = []
diff --git a/packages/core/compile_tests/props_safety.rs b/packages/core/compile_tests/props_safety.rs
new file mode 100644
index 000000000..a9729cec9
--- /dev/null
+++ b/packages/core/compile_tests/props_safety.rs
@@ -0,0 +1,32 @@
+use dioxus::prelude::*;
+
+fn main() {}
+
+fn app(cx: Scope) -> Element {
+ let count: &RefCell> = cx.use_hook(|| RefCell::new(Vec::new()));
+
+ render! {
+ unsafe_child_component {
+ borrowed: count
+ }
+ }
+}
+
+#[derive(Props)]
+struct Testing<'a> {
+ borrowed: &'a RefCell>>,
+}
+
+fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> {
+ let Testing { borrowed } = cx.props;
+ let borrowed_temporary_data =
+ cx.use_hook(|| String::from("This data is only valid for the lifetime of the child"));
+
+ borrowed
+ .borrow_mut()
+ .push(render! {"{borrowed_temporary_data}"});
+
+ cx.render(rsx! {
+ div { "Hello, world!" }
+ })
+}
diff --git a/packages/core/compile_tests/props_safety.stderr b/packages/core/compile_tests/props_safety.stderr
new file mode 100644
index 000000000..565d7b6cc
--- /dev/null
+++ b/packages/core/compile_tests/props_safety.stderr
@@ -0,0 +1,20 @@
+error[E0521]: borrowed data escapes outside of function
+ --> compile_tests/props_safety.rs:8:5
+ |
+5 | fn app(cx: Scope) -> Element {
+ | --
+ | |
+ | `cx` is a reference that is only valid in the function body
+ | has type `&'1 Scoped<'1>`
+...
+8 | / render! {
+9 | | unsafe_child_component {
+10 | | borrowed: count
+11 | | }
+12 | | }
+ | | ^
+ | | |
+ | |_____`cx` escapes the function body here
+ | argument requires that `'1` must outlive `'static`
+ |
+ = note: this error originates in the macro `render` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/packages/core/src/properties.rs b/packages/core/src/properties.rs
index 834b0cabd..05f5cbea9 100644
--- a/packages/core/src/properties.rs
+++ b/packages/core/src/properties.rs
@@ -73,3 +73,9 @@ impl EmptyBuilder {
pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element<'a>) -> T::Builder {
T::builder()
}
+
+#[test]
+fn unsafe_props_fail() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("compile_tests/props_safety.rs");
+}
From 80ac1a99afca6c465e16b37a658169edb387525e Mon Sep 17 00:00:00 2001
From: Evan Almloff
Date: Wed, 9 Aug 2023 14:20:46 -0700
Subject: [PATCH 8/9] fix miri
---
examples/props_safety.rs | 68 ---------------------------------
packages/core/src/properties.rs | 1 +
2 files changed, 1 insertion(+), 68 deletions(-)
delete mode 100644 examples/props_safety.rs
diff --git a/examples/props_safety.rs b/examples/props_safety.rs
deleted file mode 100644
index 7802e75c9..000000000
--- a/examples/props_safety.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use dioxus::prelude::*;
-
-fn main() {
- dioxus_desktop::launch(app);
-}
-
-fn app(cx: Scope) -> Element {
- let count: &RefCell> = cx.use_hook(|| RefCell::new(Vec::new()));
-
- let element = render! {
- div {
- "hello world!"
- }
- };
-
- let nested_borrows = cx.use_hook(Vec::new);
- nested_borrows.push("hello world!");
-
- cx.render(rsx! {
- // unsafe_child_component {
- // borrowed: count
- // }
- safe_child_component {
- borrowed: element
- }
- safe_nested_borrows {
- borrowed: &**nested_borrows
- }
- })
-}
-
-#[derive(Props)]
-struct NestedBorrows<'a> {
- borrowed: &'a [&'a str],
-}
-
-fn safe_nested_borrows<'a>(cx: Scope<'a, NestedBorrows<'a>>) -> Element<'a> {
- render! {
- div { "{cx.props.borrowed:?}" }
- }
-}
-
-#[derive(Props)]
-struct Testing<'a> {
- borrowed: &'a RefCell>>,
-}
-
-fn unsafe_child_component<'a>(cx: Scope<'a, Testing<'a>>) -> Element<'a> {
- let Testing { borrowed } = cx.props;
- let borrowed = borrowed.borrow();
- cx.render(rsx! {
- div { "Hello, world!" }
- })
-}
-
-#[derive(Props)]
-struct SafeTesting<'a> {
- borrowed: Element<'a>,
-}
-
-fn safe_child_component<'a>(cx: Scope<'a, SafeTesting<'a>>) -> Element<'a> {
- let SafeTesting { borrowed } = cx.props;
- cx.render(rsx! {
- div {
- borrowed
- }
- })
-}
diff --git a/packages/core/src/properties.rs b/packages/core/src/properties.rs
index 05f5cbea9..f754f8b68 100644
--- a/packages/core/src/properties.rs
+++ b/packages/core/src/properties.rs
@@ -74,6 +74,7 @@ pub fn fc_to_builder<'a, T: Properties + 'a>(_: fn(Scope<'a, T>) -> Element<'a>)
T::builder()
}
+#[cfg(not(miri))]
#[test]
fn unsafe_props_fail() {
let t = trybuild::TestCases::new();
From 2c79b7fd677da776644003afd4f54e78346edaa0 Mon Sep 17 00:00:00 2001
From: Jonathan Kelley
Date: Wed, 9 Aug 2023 15:00:57 -0700
Subject: [PATCH 9/9] Update dioxus-core to 0.4.1
---
Cargo.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/Cargo.toml b/Cargo.toml
index e6ce4459b..4c420ad3e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -54,7 +54,7 @@ version = "0.4.1"
# dependencies that are shared across packages
[workspace.dependencies]
dioxus = { path = "packages/dioxus", version = "0.4.0" }
-dioxus-core = { path = "packages/core", version = "0.4.0" }
+dioxus-core = { path = "packages/core", version = "0.4.1" }
dioxus-core-macro = { path = "packages/core-macro", version = "0.4.0" }
dioxus-router = { path = "packages/router", version = "0.4.1" }
dioxus-router-macro = { path = "packages/router-macro", version = "0.4.1" }