Skip to content

Commit 4aefdbb

Browse files
authored
Fix ?Sized type parameters in Debug (#289)
## 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.
1 parent 5b71aa0 commit 4aefdbb

File tree

2 files changed

+62
-4
lines changed

2 files changed

+62
-4
lines changed

impl/src/fmt/debug.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ fn expand_struct(
7777
.ident
7878
.clone()
7979
.map_or_else(|| syn::Member::Unnamed(i.into()), syn::Member::Named);
80-
quote! { let #var = &self.#member; }
80+
quote! { let #var = &&self.#member; }
8181
});
8282

8383
let body = quote! {

tests/debug.rs

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,7 @@ mod enums {
637637

638638
mod generic {
639639
#[cfg(not(feature = "std"))]
640-
use alloc::format;
640+
use alloc::{boxed::Box, format};
641641
use core::fmt;
642642

643643
use derive_more::Debug;
@@ -666,6 +666,22 @@ mod generic {
666666
);
667667
}
668668

669+
#[derive(Debug)]
670+
struct NamedGenericStructUnsized<T: ?Sized> {
671+
field: T,
672+
}
673+
#[test]
674+
fn named_generic_struct_unsized() {
675+
assert_eq!(
676+
format!("{:?}", NamedGenericStructUnsized { field: 1 }),
677+
"NamedGenericStructUnsized { field: 1 }",
678+
);
679+
assert_eq!(
680+
format!("{:#?}", NamedGenericStructUnsized { field: 1 }),
681+
"NamedGenericStructUnsized {\n field: 1,\n}",
682+
);
683+
}
684+
669685
#[derive(Debug)]
670686
struct NamedGenericStructIgnored<T> {
671687
#[debug(ignore)]
@@ -826,6 +842,20 @@ mod generic {
826842
);
827843
}
828844

845+
#[derive(Debug)]
846+
struct UnnamedGenericStructUnsized<T: ?Sized>(T);
847+
#[test]
848+
fn unnamed_generic_struct_unsized() {
849+
assert_eq!(
850+
format!("{:?}", UnnamedGenericStructUnsized(2)),
851+
"UnnamedGenericStructUnsized(2)",
852+
);
853+
assert_eq!(
854+
format!("{:#?}", UnnamedGenericStructUnsized(2)),
855+
"UnnamedGenericStructUnsized(\n 2,\n)",
856+
);
857+
}
858+
829859
#[derive(Debug)]
830860
struct UnnamedGenericStructIgnored<T>(#[debug(skip)] T);
831861
#[test]
@@ -910,11 +940,11 @@ mod generic {
910940
fn generic_enum() {
911941
assert_eq!(
912942
format!("{:?}", GenericEnum::A::<_, u8> { field: 1 }),
913-
"A { field: 1 }"
943+
"A { field: 1 }",
914944
);
915945
assert_eq!(
916946
format!("{:#?}", GenericEnum::A::<_, u8> { field: 1 }),
917-
"A {\n field: 1,\n}"
947+
"A {\n field: 1,\n}",
918948
);
919949
assert_eq!(format!("{:?}", GenericEnum::B::<u8, _>(2)), "B(2)");
920950
assert_eq!(
@@ -923,6 +953,34 @@ mod generic {
923953
);
924954
}
925955

956+
#[derive(derive_more::Debug)]
957+
enum GenericEnumUnsized<A: ?Sized, B: ?Sized + 'static> {
958+
A { field: Box<A> },
959+
B(&'static B),
960+
}
961+
#[test]
962+
fn generic_enum_unsized() {
963+
assert_eq!(
964+
format!("{:?}", GenericEnumUnsized::A::<i32, u8> { field: 1.into() }),
965+
"A { field: 1 }",
966+
);
967+
assert_eq!(
968+
format!(
969+
"{:#?}",
970+
GenericEnumUnsized::A::<i32, u8> { field: 1.into() },
971+
),
972+
"A {\n field: 1,\n}",
973+
);
974+
assert_eq!(
975+
format!("{:?}", GenericEnumUnsized::B::<u8, i32>(&2)),
976+
"B(2)",
977+
);
978+
assert_eq!(
979+
format!("{:#?}", GenericEnumUnsized::B::<u8, i32>(&2)),
980+
"B(\n 2,\n)",
981+
);
982+
}
983+
926984
#[derive(Debug)]
927985
enum InterpolatedGenericEnum<A, B> {
928986
A {

0 commit comments

Comments
 (0)