Skip to content

Commit

Permalink
Fix ?Sized type parameters in Debug (#289)
Browse files Browse the repository at this point in the history
## Synopsis

At the moment, `derive_more::Debug` fails to work with `?Sized`
generics:
```rust
#[derive(derive_more::Debug)]
struct UnnamedGenericStructUnsized<T: ?Sized>(T);
```
And generates the following error:
```
error[E0277]: the size for values of type `T` cannot be known at compilation time
   --> tests/debug.rs:845:14
    |
845 |     #[derive(Debug)]
    |              ^^^^^ doesn't have a size known at compile-time
846 |     struct UnnamedGenericStructUnsized<T: ?Sized>(T);
    |                                        - this type parameter needs to be `std::marker::Sized`
    |
    = note: required for the cast from `&T` to `&dyn Debug`
    = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider borrowing the value, since `&&T` can be coerced into `&dyn Debug`
    |
845 |     #[derive(&Debug)]
    |              +
help: consider removing the `?Sized` bound to make the type parameter `Sized`
    |
846 -     struct UnnamedGenericStructUnsized<T: ?Sized>(T);
846 +     struct UnnamedGenericStructUnsized<T>(T);
    |
```

At the same moment, `std::Debug` works OK:
```rust
#[derive(std::Debug)]
struct UnnamedGenericStructUnsized<T: ?Sized>(T);
```
If we look at its expansion:
```rust
#[automatically_derived]
impl<T: ::core::fmt::Debug + ?Sized> ::core::fmt::Debug for
    UnnamedGenericStructUnsized<T> {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_tuple_field1_finish(f,
            "UnnamedGenericStructUnsized", &&self.0)
    }
}
```
We can see that `std::Debug` always uses fields as `&&self.0`, while we
in our `derive_more::Debug` expansion [use `&self.0`
only](https://github.com/JelteF/derive_more/blob/v1.0.0-beta.3/impl/src/fmt/debug.rs#L80).




## Solution

Simply use double-ref in the expansion, as the error suggests, and
`std::Debug` does.
  • Loading branch information
tyranron authored Aug 14, 2023
1 parent 5b71aa0 commit 4aefdbb
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 4 deletions.
2 changes: 1 addition & 1 deletion impl/src/fmt/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fn expand_struct(
.ident
.clone()
.map_or_else(|| syn::Member::Unnamed(i.into()), syn::Member::Named);
quote! { let #var = &self.#member; }
quote! { let #var = &&self.#member; }
});

let body = quote! {
Expand Down
64 changes: 61 additions & 3 deletions tests/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ mod enums {

mod generic {
#[cfg(not(feature = "std"))]
use alloc::format;
use alloc::{boxed::Box, format};
use core::fmt;

use derive_more::Debug;
Expand Down Expand Up @@ -666,6 +666,22 @@ mod generic {
);
}

#[derive(Debug)]
struct NamedGenericStructUnsized<T: ?Sized> {
field: T,
}
#[test]
fn named_generic_struct_unsized() {
assert_eq!(
format!("{:?}", NamedGenericStructUnsized { field: 1 }),
"NamedGenericStructUnsized { field: 1 }",
);
assert_eq!(
format!("{:#?}", NamedGenericStructUnsized { field: 1 }),
"NamedGenericStructUnsized {\n field: 1,\n}",
);
}

#[derive(Debug)]
struct NamedGenericStructIgnored<T> {
#[debug(ignore)]
Expand Down Expand Up @@ -826,6 +842,20 @@ mod generic {
);
}

#[derive(Debug)]
struct UnnamedGenericStructUnsized<T: ?Sized>(T);
#[test]
fn unnamed_generic_struct_unsized() {
assert_eq!(
format!("{:?}", UnnamedGenericStructUnsized(2)),
"UnnamedGenericStructUnsized(2)",
);
assert_eq!(
format!("{:#?}", UnnamedGenericStructUnsized(2)),
"UnnamedGenericStructUnsized(\n 2,\n)",
);
}

#[derive(Debug)]
struct UnnamedGenericStructIgnored<T>(#[debug(skip)] T);
#[test]
Expand Down Expand Up @@ -910,11 +940,11 @@ mod generic {
fn generic_enum() {
assert_eq!(
format!("{:?}", GenericEnum::A::<_, u8> { field: 1 }),
"A { field: 1 }"
"A { field: 1 }",
);
assert_eq!(
format!("{:#?}", GenericEnum::A::<_, u8> { field: 1 }),
"A {\n field: 1,\n}"
"A {\n field: 1,\n}",
);
assert_eq!(format!("{:?}", GenericEnum::B::<u8, _>(2)), "B(2)");
assert_eq!(
Expand All @@ -923,6 +953,34 @@ mod generic {
);
}

#[derive(derive_more::Debug)]
enum GenericEnumUnsized<A: ?Sized, B: ?Sized + 'static> {
A { field: Box<A> },
B(&'static B),
}
#[test]
fn generic_enum_unsized() {
assert_eq!(
format!("{:?}", GenericEnumUnsized::A::<i32, u8> { field: 1.into() }),
"A { field: 1 }",
);
assert_eq!(
format!(
"{:#?}",
GenericEnumUnsized::A::<i32, u8> { field: 1.into() },
),
"A {\n field: 1,\n}",
);
assert_eq!(
format!("{:?}", GenericEnumUnsized::B::<u8, i32>(&2)),
"B(2)",
);
assert_eq!(
format!("{:#?}", GenericEnumUnsized::B::<u8, i32>(&2)),
"B(\n 2,\n)",
);
}

#[derive(Debug)]
enum InterpolatedGenericEnum<A, B> {
A {
Expand Down

0 comments on commit 4aefdbb

Please sign in to comment.