Skip to content

Fix too restrictive Clone bounds in props with generics#5451

Merged
ealmloff merged 3 commits intoDioxusLabs:mainfrom
Gohla:manual-clone
Apr 6, 2026
Merged

Fix too restrictive Clone bounds in props with generics#5451
ealmloff merged 3 commits intoDioxusLabs:mainfrom
Gohla:manual-clone

Conversation

@Gohla
Copy link
Copy Markdown
Contributor

@Gohla Gohla commented Apr 6, 2026

Currently, if you use a generic in props, the generic must be bounded by Clone even if it doesn't need to. For example:

#[component]
pub fn Table<D: AsTable + PartialEq + 'static>(data: ReadSignal<D>) -> Element {
    ...
}

fails with:

error[E0277]: the trait bound `D: Clone` is not satisfied
   --> client_dioxus\src\component\table.rs:20:8
    |
 20 | pub fn Table<D: AsTable + PartialEq + 'static>(data: ReadSignal<D>) -> Element {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `D`
    |
note: required for `TablePropsWithOwner<D>` to implement `Clone`

But D does not need to be Clone because I'm using it as ReadSignal<D>, which has a Clone impl that does not require D to be Clone. This is caused by the generated TablePropsWithOwner<D> struct using #[derive(Clone)], which generates a Clone impl where all generics are bounded by Clone (an unfortunate limitation of the standard derive).

This PR replaces #[derive(Clone)] with a Clone impl that doesn't add those bounds, fixing the above error.

@Gohla Gohla requested a review from a team as a code owner April 6, 2026 13:30
@ealmloff
Copy link
Copy Markdown
Member

ealmloff commented Apr 6, 2026

This looks like a subset of rust-lang/rust#26925 (comment). Unfortunately I don't think there is a general solution for this that handles all of these cases:

  1. The field type is private
  2. The field doesn't require the clone bound
  3. The field does require the clone bound

@Gohla
Copy link
Copy Markdown
Contributor Author

Gohla commented Apr 6, 2026

Indeed, ReadSignal<D>: Clone would be the perfect bound, but in general that type could be private.

Note that using a prop that doesn't implement Clone still gives the same error. For example:

#[component]
pub fn Table<D: AsTable + PartialEq + 'static>(data: D) -> Element {
    ...
}

still emits:

error[E0277]: the trait bound `D: Clone` is not satisfied
  --> client_dioxus\src\component\table.rs:8:1
   |
 8 | #[component]
   | ^^^^^^^^^^^^
   | |
   | the trait `Clone` is not implemented for `D`
   | in this attribute macro expansion
   |
  ::: ...\core-macro\src\lib.rs:37:1
   |
37 | pub fn component(_args: TokenStream, input: TokenStream) -> TokenStream {
   | ----------------------------------------------------------------------- in this expansion of `#[component]`
   |
help: consider further restricting type parameter `D` with trait `Clone`
   |
 9 | pub fn Table<D: AsTable + PartialEq + 'static + std::clone::Clone>(data: D) -> Element {
   |                                               +++++++++++++++++++

So omitting those bounds from the generated Clone impl doesn't weaken any guarantees. This is similar to this PR: #3968 but applied to the *WithOwner struct.

I had a look at the failing test, but can't trigger that error locally, although I am on Windows.

Copy link
Copy Markdown
Member

@ealmloff ealmloff left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! this is different from the general perfect derive case since we know both already implement clone (via clone bound on props and owners always being clone) so my comment wasn't an issue. added some tests to make sure we don't require extra generic bounds in the future

@ealmloff ealmloff merged commit a07b406 into DioxusLabs:main Apr 6, 2026
21 checks passed
@ealmloff ealmloff added the core relating to the core implementation of the virtualdom label Apr 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core relating to the core implementation of the virtualdom

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants