From bbafa6fa65a3877f34d1278792aa0b692c3b6a43 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 14:40:09 +0000 Subject: [PATCH 01/18] Debug impl: pass whole ast to create_format_arg We'll want this in a moment. No functional chnage. --- src/trait_handlers/debug/common.rs | 6 +++--- src/trait_handlers/debug/debug_enum.rs | 8 ++++---- src/trait_handlers/debug/debug_struct.rs | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/trait_handlers/debug/common.rs b/src/trait_handlers/debug/common.rs index da02c5c..ad3301f 100644 --- a/src/trait_handlers/debug/common.rs +++ b/src/trait_handlers/debug/common.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use quote::quote; -use syn::{punctuated::Punctuated, token::Comma, GenericParam, Path, Type}; +use syn::{punctuated::Punctuated, token::Comma, DeriveInput, GenericParam, Path, Type}; use crate::common::r#type::{dereference, find_idents_in_type}; @@ -23,7 +23,7 @@ pub(crate) fn create_debug_map_builder() -> proc_macro2::TokenStream { #[inline] pub(crate) fn create_format_arg( - params: &Punctuated, + ast: &DeriveInput, ty: &Type, format_method: &Path, field: proc_macro2::TokenStream, @@ -36,7 +36,7 @@ pub(crate) fn create_format_arg( // simply support one level generics (without considering bounds that use other generics) let mut filtered_params: Punctuated = Punctuated::new(); - for param in params.iter() { + for param in ast.generics.params.iter() { if let GenericParam::Type(ty) = param { let ident = &ty.ident; diff --git a/src/trait_handlers/debug/debug_enum.rs b/src/trait_handlers/debug/debug_enum.rs index 7aad9dd..1391693 100644 --- a/src/trait_handlers/debug/debug_enum.rs +++ b/src/trait_handlers/debug/debug_enum.rs @@ -110,7 +110,7 @@ impl TraitHandler for DebugEnumHandler { if let Some(method) = field_attribute.method { block_token_stream.extend(super::common::create_format_arg( - &ast.generics.params, + ast, ty, &method, quote!(#field_name_var), @@ -162,7 +162,7 @@ impl TraitHandler for DebugEnumHandler { if let Some(method) = field_attribute.method { block_token_stream.extend(super::common::create_format_arg( - &ast.generics.params, + ast, ty, &method, quote!(#field_name_var), @@ -230,7 +230,7 @@ impl TraitHandler for DebugEnumHandler { if let Some(method) = field_attribute.method { block_token_stream.extend(super::common::create_format_arg( - &ast.generics.params, + ast, ty, &method, quote!(#field_name_var), @@ -280,7 +280,7 @@ impl TraitHandler for DebugEnumHandler { if let Some(method) = field_attribute.method { block_token_stream.extend(super::common::create_format_arg( - &ast.generics.params, + ast, ty, &method, quote!(#field_name_var), diff --git a/src/trait_handlers/debug/debug_struct.rs b/src/trait_handlers/debug/debug_struct.rs index b435a15..55f2b44 100644 --- a/src/trait_handlers/debug/debug_struct.rs +++ b/src/trait_handlers/debug/debug_struct.rs @@ -80,7 +80,7 @@ impl TraitHandler for DebugStructHandler { if let Some(method) = field_attribute.method { builder_token_stream.extend(super::common::create_format_arg( - &ast.generics.params, + ast, ty, &method, quote!(&self.#field_name), @@ -129,7 +129,7 @@ impl TraitHandler for DebugStructHandler { if let Some(method) = field_attribute.method { builder_token_stream.extend(super::common::create_format_arg( - &ast.generics.params, + ast, ty, &method, quote!(&self.#field_name), From e224ad8b5708431f738ffbcf295b57e8ea9fedf4 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 14:41:25 +0000 Subject: [PATCH 02/18] Debug impl: Fix generated code for explicit methods * Make the internal wrapper type have *all* the parent's generics, and contain a PhantomData, so we can: * Put the bounds on the Debug impl for the internal wrapper type. * Rename the internal wrapper type to avoid name clashes with users' types. * Rename the formatter variable to avoid name clashes with users's values. --- src/trait_handlers/debug/common.rs | 47 ++++++++++++------------------ 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/src/trait_handlers/debug/common.rs b/src/trait_handlers/debug/common.rs index ad3301f..3b55b25 100644 --- a/src/trait_handlers/debug/common.rs +++ b/src/trait_handlers/debug/common.rs @@ -1,9 +1,5 @@ -use std::collections::HashSet; - use quote::quote; -use syn::{punctuated::Punctuated, token::Comma, DeriveInput, GenericParam, Path, Type}; - -use crate::common::r#type::{dereference, find_idents_in_type}; +use syn::{DeriveInput, Path, Type}; #[inline] pub(crate) fn create_debug_map_builder() -> proc_macro2::TokenStream { @@ -24,40 +20,35 @@ pub(crate) fn create_debug_map_builder() -> proc_macro2::TokenStream { #[inline] pub(crate) fn create_format_arg( ast: &DeriveInput, - ty: &Type, + field_ty: &Type, format_method: &Path, - field: proc_macro2::TokenStream, + field_expr: proc_macro2::TokenStream, ) -> proc_macro2::TokenStream { - let ty = dereference(ty); - - let mut idents = HashSet::new(); - find_idents_in_type(&mut idents, ty, Some((true, true, false))); - - // simply support one level generics (without considering bounds that use other generics) - let mut filtered_params: Punctuated = Punctuated::new(); + let ty_ident = &ast.ident; - for param in ast.generics.params.iter() { - if let GenericParam::Type(ty) = param { - let ident = &ty.ident; - - if idents.contains(ident) { - filtered_params.push(param.clone()); - } - } - } + // We use the complete original generics, not filtered by field, + // and include a PhantomData in our wrapper struct to use the generics. + // + // This avoids having to try to calculate the right *subset* of the generics + // relevant for this field, which is nontrivial and maybe impossible. + let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl(); quote!( let arg = { - struct MyDebug<'a, #filtered_params>(&'a #ty); + #[allow(non_camel_case_types)] // We're using __ to help avoid clashes. + struct Educe__DebugField(V, ::core::marker::PhantomData); - impl<'a, #filtered_params> ::core::fmt::Debug for MyDebug<'a, #filtered_params> { + impl #impl_generics ::core::fmt::Debug + for Educe__DebugField<&#field_ty, #ty_ident #ty_generics> + #where_clause + { #[inline] - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - #format_method(self.0, f) + fn fmt(&self, educe__f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + #format_method(self.0, educe__f) } } - MyDebug(#field) + Educe__DebugField(#field_expr, ::core::marker::PhantomData::) }; ) } From dea0d337ec7fefe56b4e726bc81bb93ebbfd2fa1 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 11:38:08 +0000 Subject: [PATCH 03/18] Default bounds: Use precisely the right bounds, from the fields Rather than trying to filter the generic parameters for ones used in types, state the bounds in terms of the actual field types. This is precisely correct. It avoids lossage in situations where the field type's implementation of the trait has bounds which depend in a less-than-straightforward way on its generics. There is still an issue with implementing traits which have supertraits. We ought to apply a `Self: Super` bound, but we don't yet. --- src/common/where_predicates_bool.rs | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/common/where_predicates_bool.rs b/src/common/where_predicates_bool.rs index 614c34b..5ad8c4b 100644 --- a/src/common/where_predicates_bool.rs +++ b/src/common/where_predicates_bool.rs @@ -1,5 +1,3 @@ -use std::collections::HashSet; - use quote::{quote, ToTokens}; use syn::{ parse::{Parse, ParseStream}, @@ -9,7 +7,7 @@ use syn::{ Expr, GenericParam, Lit, Meta, MetaNameValue, Path, Token, Type, WherePredicate, }; -use super::{path::path_to_string, r#type::find_idents_in_type}; +use super::path::path_to_string; pub(crate) type WherePredicates = Punctuated; @@ -108,27 +106,15 @@ pub(crate) fn create_where_predicates_from_generic_parameters( #[inline] pub(crate) fn create_where_predicates_from_generic_parameters_check_types( - params: &Punctuated, + _params: &Punctuated, bound_trait: &Path, types: &[&Type], - recursive: Option<(bool, bool, bool)>, + _recursive: Option<(bool, bool, bool)>, ) -> WherePredicates { let mut where_predicates = Punctuated::new(); - let mut set = HashSet::new(); - for t in types { - find_idents_in_type(&mut set, t, recursive); - } - - for param in params { - if let GenericParam::Type(ty) = param { - let ident = &ty.ident; - - if set.contains(ident) { - where_predicates.push(syn::parse2(quote! { #ident: #bound_trait }).unwrap()); - } - } + where_predicates.push(syn::parse2(quote! { #t: #bound_trait }).unwrap()); } where_predicates From b2a99a70ee8a5ea1e76903defabdb5d36af3245e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 11:51:37 +0000 Subject: [PATCH 04/18] Debug: Demonstrate generic type bounds in a test --- tests/debug_struct.rs | 59 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/debug_struct.rs b/tests/debug_struct.rs index 23fceff..4cd8573 100644 --- a/tests/debug_struct.rs +++ b/tests/debug_struct.rs @@ -4,6 +4,11 @@ #[macro_use] extern crate alloc; +use core::{ + fmt::{self, Debug, Display}, + marker::PhantomData, +}; + use educe::Educe; #[test] @@ -532,3 +537,57 @@ fn bound_3() { assert_eq!("Tuple(1)", format!("{:?}", Tuple(1))); } + +#[test] +fn bound_4() { + use core::cell::RefCell; + + #[derive(Educe)] + #[educe(Debug)] + struct Struct { + f1: RefCell, + } + + assert_eq!( + "Struct { f1: RefCell { value: 1 } }", + format!("{:?}", Struct { + f1: RefCell::new(1) + }) + ); + + #[derive(Educe)] + #[educe(Debug(bound(T: core::fmt::Debug)))] + struct Tuple(RefCell); + + assert_eq!("Tuple(RefCell { value: 1 })", format!("{:?}", Tuple(RefCell::new(1)))); +} + +#[test] +fn bound_5() { + struct DebugAsDisplay(T); + + struct NotDebug; + + impl Debug for DebugAsDisplay { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } + } + + #[derive(Educe)] + #[educe(Debug)] + struct Struct { + f1: Option, + f2: DebugAsDisplay, + f3: PhantomData, + } + + assert_eq!( + "Struct { f1: Some(1), f2: lit, f3: PhantomData }", + format!("{:?}", Struct { + f1: Some(1), + f2: DebugAsDisplay("lit"), + f3: PhantomData::, + }) + ); +} From 610b6adacd00d3c4b25f5e257687b11bc82e8bb0 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 12:20:15 +0000 Subject: [PATCH 05/18] Generic bounds: Handle supertraits When we are implementing traits which have supertraits, add bounds of the form `where Self: Super` for each supertrait. While we're touching every call site, abolish the unused parameters. (I have future plans that will want `params` in into_where_predicates_by_generic_parameters_check_types, but not in create_where_predicates_from_generic_parameters_check_types, so leave that one there for now.) --- src/common/bound.rs | 7 +++---- src/common/where_predicates_bool.rs | 7 +++++-- src/trait_handlers/clone/clone_enum.rs | 2 +- src/trait_handlers/clone/clone_struct.rs | 2 +- src/trait_handlers/debug/debug_enum.rs | 2 +- src/trait_handlers/debug/debug_struct.rs | 2 +- src/trait_handlers/default/default_enum.rs | 2 +- src/trait_handlers/default/default_struct.rs | 2 +- src/trait_handlers/default/default_union.rs | 2 +- src/trait_handlers/hash/hash_enum.rs | 2 +- src/trait_handlers/hash/hash_struct.rs | 2 +- src/trait_handlers/into/into_enum.rs | 2 +- src/trait_handlers/into/into_struct.rs | 2 +- src/trait_handlers/ord/mod.rs | 15 +++++++++++++++ src/trait_handlers/ord/ord_enum.rs | 2 +- src/trait_handlers/ord/ord_struct.rs | 2 +- src/trait_handlers/partial_eq/partial_eq_enum.rs | 2 +- .../partial_eq/partial_eq_struct.rs | 2 +- .../partial_ord/partial_ord_enum.rs | 2 +- .../partial_ord/partial_ord_struct.rs | 2 +- 20 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/common/bound.rs b/src/common/bound.rs index 6ee7a74..3dac605 100644 --- a/src/common/bound.rs +++ b/src/common/bound.rs @@ -49,18 +49,17 @@ impl Bound { #[inline] pub(crate) fn into_where_predicates_by_generic_parameters_check_types( self, - params: &Punctuated, + _params: &Punctuated, bound_trait: &Path, types: &[&Type], - recursive: Option<(bool, bool, bool)>, + supertraits: &[proc_macro2::TokenStream], ) -> Punctuated { match self { Self::Disabled => Punctuated::new(), Self::Auto => create_where_predicates_from_generic_parameters_check_types( - params, bound_trait, types, - recursive, + supertraits, ), Self::Custom(where_predicates) => where_predicates, } diff --git a/src/common/where_predicates_bool.rs b/src/common/where_predicates_bool.rs index 5ad8c4b..f0b9464 100644 --- a/src/common/where_predicates_bool.rs +++ b/src/common/where_predicates_bool.rs @@ -106,10 +106,9 @@ pub(crate) fn create_where_predicates_from_generic_parameters( #[inline] pub(crate) fn create_where_predicates_from_generic_parameters_check_types( - _params: &Punctuated, bound_trait: &Path, types: &[&Type], - _recursive: Option<(bool, bool, bool)>, + supertraits: &[proc_macro2::TokenStream], ) -> WherePredicates { let mut where_predicates = Punctuated::new(); @@ -117,5 +116,9 @@ pub(crate) fn create_where_predicates_from_generic_parameters_check_types( where_predicates.push(syn::parse2(quote! { #t: #bound_trait }).unwrap()); } + for supertrait in supertraits { + where_predicates.push(syn::parse2(quote! { Self: #supertrait }).unwrap()); + } + where_predicates } diff --git a/src/trait_handlers/clone/clone_enum.rs b/src/trait_handlers/clone/clone_enum.rs index 8cd7d1b..19b4d24 100644 --- a/src/trait_handlers/clone/clone_enum.rs +++ b/src/trait_handlers/clone/clone_enum.rs @@ -222,7 +222,7 @@ impl TraitHandler for CloneEnumHandler { }) .unwrap(), &clone_types, - Some((false, false, false)), + &[], ); } diff --git a/src/trait_handlers/clone/clone_struct.rs b/src/trait_handlers/clone/clone_struct.rs index 6f07f72..12bc279 100644 --- a/src/trait_handlers/clone/clone_struct.rs +++ b/src/trait_handlers/clone/clone_struct.rs @@ -145,7 +145,7 @@ impl TraitHandler for CloneStructHandler { }) .unwrap(), &clone_types, - Some((false, false, false)), + &[], ); } diff --git a/src/trait_handlers/debug/debug_enum.rs b/src/trait_handlers/debug/debug_enum.rs index 1391693..3132928 100644 --- a/src/trait_handlers/debug/debug_enum.rs +++ b/src/trait_handlers/debug/debug_enum.rs @@ -336,7 +336,7 @@ impl TraitHandler for DebugEnumHandler { &ast.generics.params, &syn::parse2(quote!(::core::fmt::Debug)).unwrap(), &debug_types, - Some((true, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/debug/debug_struct.rs b/src/trait_handlers/debug/debug_struct.rs index 55f2b44..550226d 100644 --- a/src/trait_handlers/debug/debug_struct.rs +++ b/src/trait_handlers/debug/debug_struct.rs @@ -157,7 +157,7 @@ impl TraitHandler for DebugStructHandler { &ast.generics.params, &syn::parse2(quote!(::core::fmt::Debug)).unwrap(), &debug_types, - Some((true, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/default/default_enum.rs b/src/trait_handlers/default/default_enum.rs index f1721b3..bac7767 100644 --- a/src/trait_handlers/default/default_enum.rs +++ b/src/trait_handlers/default/default_enum.rs @@ -166,7 +166,7 @@ impl TraitHandler for DefaultEnumHandler { &ast.generics.params, &syn::parse2(quote!(::core::default::Default)).unwrap(), &default_types, - Some((false, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/default/default_struct.rs b/src/trait_handlers/default/default_struct.rs index bf29c26..ece7720 100644 --- a/src/trait_handlers/default/default_struct.rs +++ b/src/trait_handlers/default/default_struct.rs @@ -111,7 +111,7 @@ impl TraitHandler for DefaultStructHandler { &ast.generics.params, &syn::parse2(quote!(::core::default::Default)).unwrap(), &default_types, - Some((false, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/default/default_union.rs b/src/trait_handlers/default/default_union.rs index 18b3760..371d38e 100644 --- a/src/trait_handlers/default/default_union.rs +++ b/src/trait_handlers/default/default_union.rs @@ -115,7 +115,7 @@ impl TraitHandler for DefaultUnionHandler { &ast.generics.params, &syn::parse2(quote!(::core::default::Default)).unwrap(), &default_types, - Some((false, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/hash/hash_enum.rs b/src/trait_handlers/hash/hash_enum.rs index 0107056..06b04dc 100644 --- a/src/trait_handlers/hash/hash_enum.rs +++ b/src/trait_handlers/hash/hash_enum.rs @@ -143,7 +143,7 @@ impl TraitHandler for HashEnumHandler { &ast.generics.params, &syn::parse2(quote!(::core::hash::Hash)).unwrap(), &hash_types, - Some((true, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/hash/hash_struct.rs b/src/trait_handlers/hash/hash_struct.rs index d6c30a6..bafb6c5 100644 --- a/src/trait_handlers/hash/hash_struct.rs +++ b/src/trait_handlers/hash/hash_struct.rs @@ -62,7 +62,7 @@ impl TraitHandler for HashStructHandler { &ast.generics.params, &syn::parse2(quote!(::core::hash::Hash)).unwrap(), &hash_types, - Some((true, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/into/into_enum.rs b/src/trait_handlers/into/into_enum.rs index 46d72dd..12fcd19 100644 --- a/src/trait_handlers/into/into_enum.rs +++ b/src/trait_handlers/into/into_enum.rs @@ -192,7 +192,7 @@ impl TraitHandlerMultiple for IntoEnumHandler { &ast.generics.params, &syn::parse2(quote!(::core::convert::Into<#target_ty>)).unwrap(), &into_types, - None, + &[], ); // clone generics in order to not to affect other Into implementations diff --git a/src/trait_handlers/into/into_struct.rs b/src/trait_handlers/into/into_struct.rs index bd9eb36..cac39c8 100644 --- a/src/trait_handlers/into/into_struct.rs +++ b/src/trait_handlers/into/into_struct.rs @@ -138,7 +138,7 @@ impl TraitHandlerMultiple for IntoStructHandler { &ast.generics.params, &syn::parse2(quote!(::core::convert::Into<#target_ty>)).unwrap(), &into_types, - None, + &[], ); // clone generics in order to not to affect other Into implementations diff --git a/src/trait_handlers/ord/mod.rs b/src/trait_handlers/ord/mod.rs index 0913507..da9960d 100644 --- a/src/trait_handlers/ord/mod.rs +++ b/src/trait_handlers/ord/mod.rs @@ -3,6 +3,7 @@ mod ord_enum; mod ord_struct; mod panic; +use quote::quote; use syn::{Data, DeriveInput, Meta}; use super::TraitHandler; @@ -31,3 +32,17 @@ impl TraitHandler for OrdHandler { } } } + +fn supertraits(traits: &[Trait]) -> Vec { + let mut supertraits = vec![]; + supertraits.push(quote! {::core::cmp::Eq}); + + // We mustn't add the PartialOrd bound to the educed PartialOrd impl. + // When we're educing PartialOrd we can leave it off the Ord impl too, + // since we *know* Self is going to be PartialOrd. + if !traits.contains(&Trait::PartialOrd) { + supertraits.push(quote! {::core::cmp::PartialOrd}); + }; + + supertraits +} diff --git a/src/trait_handlers/ord/ord_enum.rs b/src/trait_handlers/ord/ord_enum.rs index 2ea3a1e..e9461b9 100644 --- a/src/trait_handlers/ord/ord_enum.rs +++ b/src/trait_handlers/ord/ord_enum.rs @@ -245,7 +245,7 @@ impl TraitHandler for OrdEnumHandler { &ast.generics.params, &syn::parse2(quote!(::core::cmp::Ord)).unwrap(), &ord_types, - Some((true, false, false)), + &crate::trait_handlers::ord::supertraits(traits), ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/ord/ord_struct.rs b/src/trait_handlers/ord/ord_struct.rs index ecfaf47..64d6630 100644 --- a/src/trait_handlers/ord/ord_struct.rs +++ b/src/trait_handlers/ord/ord_struct.rs @@ -83,7 +83,7 @@ impl TraitHandler for OrdStructHandler { &ast.generics.params, &syn::parse2(quote!(::core::cmp::Ord)).unwrap(), &ord_types, - Some((true, false, false)), + &crate::trait_handlers::ord::supertraits(traits), ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/partial_eq/partial_eq_enum.rs b/src/trait_handlers/partial_eq/partial_eq_enum.rs index 8ef8c6f..905c776 100644 --- a/src/trait_handlers/partial_eq/partial_eq_enum.rs +++ b/src/trait_handlers/partial_eq/partial_eq_enum.rs @@ -182,7 +182,7 @@ impl TraitHandler for PartialEqEnumHandler { &ast.generics.params, &syn::parse2(quote!(::core::cmp::PartialEq)).unwrap(), &partial_eq_types, - Some((true, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/partial_eq/partial_eq_struct.rs b/src/trait_handlers/partial_eq/partial_eq_struct.rs index 318e71b..0fd6195 100644 --- a/src/trait_handlers/partial_eq/partial_eq_struct.rs +++ b/src/trait_handlers/partial_eq/partial_eq_struct.rs @@ -67,7 +67,7 @@ impl TraitHandler for PartialEqStructHandler { &ast.generics.params, &syn::parse2(quote!(::core::cmp::PartialEq)).unwrap(), &partial_eq_types, - Some((true, false, false)), + &[], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/partial_ord/partial_ord_enum.rs b/src/trait_handlers/partial_ord/partial_ord_enum.rs index e0d9432..3e22a87 100644 --- a/src/trait_handlers/partial_ord/partial_ord_enum.rs +++ b/src/trait_handlers/partial_ord/partial_ord_enum.rs @@ -250,7 +250,7 @@ impl TraitHandler for PartialOrdEnumHandler { &ast.generics.params, &syn::parse2(quote!(::core::cmp::PartialOrd)).unwrap(), &partial_ord_types, - Some((true, false, false)), + &[quote! {::core::cmp::PartialEq}], ); let where_clause = ast.generics.make_where_clause(); diff --git a/src/trait_handlers/partial_ord/partial_ord_struct.rs b/src/trait_handlers/partial_ord/partial_ord_struct.rs index da158d7..2fa9e60 100644 --- a/src/trait_handlers/partial_ord/partial_ord_struct.rs +++ b/src/trait_handlers/partial_ord/partial_ord_struct.rs @@ -85,7 +85,7 @@ impl TraitHandler for PartialOrdStructHandler { &ast.generics.params, &syn::parse2(quote!(::core::cmp::PartialOrd)).unwrap(), &partial_ord_types, - Some((true, false, false)), + &[quote! {::core::cmp::PartialEq}], ); let where_clause = ast.generics.make_where_clause(); From eb28c48ebfa14122a9f45eb0ff0bf10dee3d8a09 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 13:53:02 +0000 Subject: [PATCH 06/18] Tests: Demonstrate supertraits when educing PartialOrd --- tests/partial_ord_struct.rs | 52 ++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/tests/partial_ord_struct.rs b/tests/partial_ord_struct.rs index bb84517..b84a862 100644 --- a/tests/partial_ord_struct.rs +++ b/tests/partial_ord_struct.rs @@ -1,7 +1,7 @@ #![cfg(feature = "PartialOrd")] #![no_std] -use core::cmp::Ordering; +use core::{cmp::Ordering, marker::PhantomData}; use educe::Educe; @@ -527,3 +527,53 @@ fn bound_3() { assert!(Tuple(2) > Tuple(1)); assert!(Tuple(1) < Tuple(2)); } + +#[test] +fn bound_4() { + trait Suitable {} + struct SuitableNotEq; + impl Suitable for SuitableNotEq {} + let phantom = PhantomData::; + + #[derive(Educe)] + #[educe(PartialOrd)] + struct Struct { + f1: T, + // PhantomData is Eq (all PhantomData are equal to all others) + f2: PhantomData, + } + + impl PartialEq for Struct { + fn eq(&self, other: &Struct) -> bool { + self.f1.eq(&other.f1) + } + } + + #[derive(Educe)] + #[educe(Eq)] + struct Tuple(T, PhantomData); + + impl PartialEq for Tuple { + fn eq(&self, other: &Tuple) -> bool { + self.0.eq(&other.0) + } + } + assert!( + Struct { + f1: 1, f2: phantom + } == Struct { + f1: 1, f2: phantom + } + ); + + assert!( + Struct { + f1: 1, f2: phantom + } != Struct { + f1: 2, f2: phantom + } + ); + + assert!(Tuple(1, phantom) == Tuple(1, phantom)); + assert!(Tuple(1, phantom) != Tuple(2, phantom)); +} From 69f4c1c7eeb754cdadf6701a14c59cfa89fccbbd Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 13:44:30 +0000 Subject: [PATCH 07/18] Tests: Demonstrate supertraits when educing Ord --- tests/ord_struct.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-) diff --git a/tests/ord_struct.rs b/tests/ord_struct.rs index efe3046..aeedfcf 100644 --- a/tests/ord_struct.rs +++ b/tests/ord_struct.rs @@ -1,7 +1,7 @@ #![cfg(all(feature = "Ord", feature = "PartialOrd"))] #![no_std] -use core::cmp::Ordering; +use core::{cmp::Ordering, marker::PhantomData}; use educe::Educe; @@ -528,6 +528,67 @@ fn bound_3() { assert!(Tuple(1) < Tuple(2)); } +#[test] +fn bound_4() { + trait Suitable {} + struct SuitableNotEq; + impl Suitable for SuitableNotEq {} + let phantom = PhantomData::; + + #[derive(Educe)] + #[educe(Ord, PartialEq)] + struct Struct { + f1: T, + // PhantomData is Eq (all PhantomData are equal to all others) + f2: PhantomData, + } + + impl Eq for Struct {} + impl PartialOrd for Struct { + fn partial_cmp(&self, other: &Struct) -> Option { + self.f1.partial_cmp(&other.f1) + } + } + + #[derive(Educe)] + #[educe(Ord, PartialEq)] + struct Tuple(T, PhantomData); + + impl Eq for Tuple {} + impl PartialOrd for Tuple { + fn partial_cmp(&self, other: &Tuple) -> Option { + self.0.partial_cmp(&other.0) + } + } + + assert_eq!( + Ord::cmp( + &Struct { + f1: 1, f2: phantom + }, + &Struct { + f1: 1, f2: phantom + } + ), + Ordering::Equal + ); + + assert_eq!( + Ord::cmp( + &Struct { + f1: 1, f2: phantom + }, + &Struct { + f1: 2, f2: phantom + } + ), + Ordering::Less + ); + + assert_eq!(Ord::cmp(&Tuple(1, phantom), &Tuple(1, phantom)), Ordering::Equal); + assert_eq!(Ord::cmp(&Tuple(1, phantom), &Tuple(2, phantom)), Ordering::Less); +} + #[test] fn use_partial_ord_attr_ignore() { #[derive(PartialEq, Eq, Educe)] From 7690e47d1391e0dc285bb574eddc4f3522718b29 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 12:38:05 +0000 Subject: [PATCH 08/18] Eq: Fix bounds Use the new precise bounds function. --- src/trait_handlers/eq/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/trait_handlers/eq/mod.rs b/src/trait_handlers/eq/mod.rs index 1c3b2a5..61ebd1f 100644 --- a/src/trait_handlers/eq/mod.rs +++ b/src/trait_handlers/eq/mod.rs @@ -29,11 +29,14 @@ impl TraitHandler for EqHandler { } .build_from_eq_meta(meta)?; + let mut field_types = vec![]; + // if `contains_partial_eq` is true, the implementation is handled by the `PartialEq` attribute, and field attributes is also handled by the `PartialEq` attribute if !contains_partial_eq { match &ast.data { Data::Struct(data) => { for field in data.fields.iter() { + field_types.push(&field.ty); let _ = FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?; } @@ -46,6 +49,7 @@ impl TraitHandler for EqHandler { .build_from_attributes(&variant.attrs, traits)?; for field in variant.fields.iter() { + field_types.push(&field.ty); let _ = FieldAttributeBuilder .build_from_attributes(&field.attrs, traits)?; } @@ -53,6 +57,7 @@ impl TraitHandler for EqHandler { }, Data::Union(data) => { for field in data.fields.named.iter() { + field_types.push(&field.ty); let _ = FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?; } @@ -73,9 +78,11 @@ impl TraitHandler for EqHandler { // The above code will throw a compile error because T have to be bound to `PartialEq`. However, it seems not to be necessary logically. */ - let bound = type_attribute.bound.into_where_predicates_by_generic_parameters( + let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( &ast.generics.params, &syn::parse2(quote!(::core::cmp::PartialEq)).unwrap(), + &field_types, + &[quote!{::core::cmp::PartialEq}], ); let where_clause = ast.generics.make_where_clause(); From 2e47d8b21a42beca357208866901773ed7f6b714 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 15:28:21 +0000 Subject: [PATCH 09/18] Eq: Fix bounds (rustfmt) --- src/trait_handlers/eq/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/trait_handlers/eq/mod.rs b/src/trait_handlers/eq/mod.rs index 61ebd1f..ff722e1 100644 --- a/src/trait_handlers/eq/mod.rs +++ b/src/trait_handlers/eq/mod.rs @@ -78,12 +78,13 @@ impl TraitHandler for EqHandler { // The above code will throw a compile error because T have to be bound to `PartialEq`. However, it seems not to be necessary logically. */ - let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( - &ast.generics.params, - &syn::parse2(quote!(::core::cmp::PartialEq)).unwrap(), - &field_types, - &[quote!{::core::cmp::PartialEq}], - ); + let bound = + type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( + &ast.generics.params, + &syn::parse2(quote!(::core::cmp::PartialEq)).unwrap(), + &field_types, + &[quote! {::core::cmp::PartialEq}], + ); let where_clause = ast.generics.make_where_clause(); From 725dae8a5e405a528f4aaad4fa9751c51249dc74 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 12:34:16 +0000 Subject: [PATCH 10/18] Eq: Demonstrate precise bounds in a test --- tests/eq_struct.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/eq_struct.rs b/tests/eq_struct.rs index 6730fbc..e8d96a4 100644 --- a/tests/eq_struct.rs +++ b/tests/eq_struct.rs @@ -1,6 +1,8 @@ #![cfg(all(feature = "Eq", feature = "PartialEq"))] #![no_std] +use core::marker::PhantomData; + use educe::Educe; #[test] @@ -333,6 +335,56 @@ fn bound_3() { assert!(Tuple(1) != Tuple(2)); } +#[test] +fn bound_4() { + trait Suitable {} + struct SuitableNotEq; + impl Suitable for SuitableNotEq {} + let phantom = PhantomData::; + + #[derive(Educe)] + #[educe(Eq)] + struct Struct { + f1: T, + // PhantomData is Eq (all PhantomData are equal to all others) + f2: PhantomData, + } + + impl PartialEq for Struct { + fn eq(&self, other: &Struct) -> bool { + self.f1.eq(&other.f1) + } + } + + #[derive(Educe)] + #[educe(Eq)] + struct Tuple(T, PhantomData); + + impl PartialEq for Tuple { + fn eq(&self, other: &Tuple) -> bool { + self.0.eq(&other.0) + } + } + assert!( + Struct { + f1: 1, f2: phantom + } == Struct { + f1: 1, f2: phantom + } + ); + + assert!( + Struct { + f1: 1, f2: phantom + } != Struct { + f1: 2, f2: phantom + } + ); + + assert!(Tuple(1, phantom) == Tuple(1, phantom)); + assert!(Tuple(1, phantom) != Tuple(2, phantom)); +} + #[allow(dead_code)] #[test] fn use_partial_eq_attr_ignore() { From b18f14f15a89be3bd8cf3aecf71f6666af27606e Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 12:19:10 +0000 Subject: [PATCH 11/18] Copy: Fix bounds Use the new precise bounds function, rather than the ident-hunter. Apply the Clone supertrait explicitly. This disposes of the oddity mentioned in the comment, as will be demonstrated in a test. --- src/trait_handlers/copy/mod.rs | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/trait_handlers/copy/mod.rs b/src/trait_handlers/copy/mod.rs index 8c3259f..38e833d 100644 --- a/src/trait_handlers/copy/mod.rs +++ b/src/trait_handlers/copy/mod.rs @@ -29,11 +29,14 @@ impl TraitHandler for CopyHandler { } .build_from_copy_meta(meta)?; + let mut field_types = vec![]; + // if `contains_clone` is true, the implementation is handled by the `Clone` attribute, and field attributes is also handled by the `Clone` attribute if !contains_clone { match &ast.data { Data::Struct(data) => { for field in data.fields.iter() { + field_types.push(&field.ty); let _ = FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?; } @@ -46,6 +49,7 @@ impl TraitHandler for CopyHandler { .build_from_attributes(&variant.attrs, traits)?; for field in variant.fields.iter() { + field_types.push(&field.ty); let _ = FieldAttributeBuilder .build_from_attributes(&field.attrs, traits)?; } @@ -53,6 +57,7 @@ impl TraitHandler for CopyHandler { }, Data::Union(data) => { for field in data.fields.named.iter() { + field_types.push(&field.ty); let _ = FieldAttributeBuilder.build_from_attributes(&field.attrs, traits)?; } @@ -61,21 +66,11 @@ impl TraitHandler for CopyHandler { let ident = &ast.ident; - /* - #[derive(Clone)] - struct B { - f1: PhantomData, - } - - impl Copy for B { - - } - - // The above code will throw a compile error because T have to be bound to `Copy`. However, it seems not to be necessary logically. - */ - let bound = type_attribute.bound.into_where_predicates_by_generic_parameters( + let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( &ast.generics.params, &syn::parse2(quote!(::core::marker::Copy)).unwrap(), + &field_types, + &[quote!{::core::clone::Clone}], ); let where_clause = ast.generics.make_where_clause(); From 9a290801a4e1e129dfab7ba4de24a4734178adaa Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 15:29:13 +0000 Subject: [PATCH 12/18] Copy: Fix bounds (rustfmt) --- src/trait_handlers/copy/mod.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/trait_handlers/copy/mod.rs b/src/trait_handlers/copy/mod.rs index 38e833d..02e0e62 100644 --- a/src/trait_handlers/copy/mod.rs +++ b/src/trait_handlers/copy/mod.rs @@ -66,12 +66,13 @@ impl TraitHandler for CopyHandler { let ident = &ast.ident; - let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( - &ast.generics.params, - &syn::parse2(quote!(::core::marker::Copy)).unwrap(), - &field_types, - &[quote!{::core::clone::Clone}], - ); + let bound = + type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( + &ast.generics.params, + &syn::parse2(quote!(::core::marker::Copy)).unwrap(), + &field_types, + &[quote! {::core::clone::Clone}], + ); let where_clause = ast.generics.make_where_clause(); From 1daf89364b4ed2f01d1e15f68c74466883f74127 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 11:59:15 +0000 Subject: [PATCH 13/18] Copy, Clone: Demonstrate precise bounds in tests --- tests/copy_clone_struct.rs | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/copy_clone_struct.rs b/tests/copy_clone_struct.rs index 0b3c3dd..69f3088 100644 --- a/tests/copy_clone_struct.rs +++ b/tests/copy_clone_struct.rs @@ -2,6 +2,8 @@ #![no_std] #![allow(clippy::clone_on_copy)] +use core::marker::PhantomData; + use educe::Educe; #[test] @@ -109,3 +111,72 @@ fn bound_3() { assert_eq!(1, s.f1); assert_eq!(1, t.0); } + +#[test] +fn bound_4() { + #[derive(Educe)] + #[educe(Copy, Clone)] + struct Struct { + f1: Option, + f2: PhantomData, + } + + #[derive(Educe)] + #[educe(Copy, Clone)] + struct Tuple(Option, PhantomData); + + let s = Struct { + f1: Some(1), f2: PhantomData:: + } + .clone(); + let t = Tuple(Some(1), PhantomData::).clone(); + + assert_eq!(Some(1), s.f1); + assert_eq!(Some(1), t.0); +} + +#[test] +fn bound_5() { + trait Suitable {} + struct SuitableNotClone; + impl Suitable for SuitableNotClone {} + let phantom = PhantomData::; + + fn copy(t: &T) -> T { + *t + } + + #[derive(Educe)] + #[educe(Copy)] + struct Struct { + f1: Option, + f2: PhantomData, + } + + impl Clone for Struct { + fn clone(&self) -> Self { + Struct { + f1: self.f1.clone(), f2: PhantomData + } + } + } + + #[derive(Educe)] + #[educe(Copy)] + struct Tuple(Option, PhantomData); + + impl Clone for Tuple { + fn clone(&self) -> Self { + Tuple(self.0.clone(), PhantomData) + } + } + + let s = copy(&Struct { + f1: Some(1), f2: phantom + }); + + let t = copy(&Tuple(Some(1), phantom)); + + assert_eq!(Some(1), s.f1); + assert_eq!(Some(1), t.0); +} From 1a09812d24f27f5452ebb603d0cf42371620de2b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 12:24:39 +0000 Subject: [PATCH 14/18] Clone of unions: Fix bounds Use the new precise bounds function. --- src/trait_handlers/clone/clone_union.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/trait_handlers/clone/clone_union.rs b/src/trait_handlers/clone/clone_union.rs index 6d2986b..9b2968c 100644 --- a/src/trait_handlers/clone/clone_union.rs +++ b/src/trait_handlers/clone/clone_union.rs @@ -21,8 +21,11 @@ impl TraitHandler for CloneUnionHandler { } .build_from_clone_meta(meta)?; + let mut field_types = vec![]; + if let Data::Union(data) = &ast.data { for field in data.fields.named.iter() { + field_types.push(&field.ty); let _ = FieldAttributeBuilder { enable_method: false } @@ -32,9 +35,11 @@ impl TraitHandler for CloneUnionHandler { let ident = &ast.ident; - let bound = type_attribute.bound.into_where_predicates_by_generic_parameters( + let bound = type_attribute.bound.into_where_predicates_by_generic_parameters_check_types( &ast.generics.params, &syn::parse2(quote!(::core::marker::Copy)).unwrap(), + &field_types, + &[], ); let where_clause = ast.generics.make_where_clause(); From f3a3cb5690c2e0facfe6fa2b4883656605202e84 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 11:39:45 +0000 Subject: [PATCH 15/18] Abolish find_idents_* This is no longer used, now that everything uses the precise bounds function. --- src/common/type.rs | 113 +-------------------------------------------- 1 file changed, 1 insertion(+), 112 deletions(-) diff --git a/src/common/type.rs b/src/common/type.rs index e6fd1d0..c17ed73 100644 --- a/src/common/type.rs +++ b/src/common/type.rs @@ -1,9 +1,7 @@ -use std::collections::HashSet; - use syn::{ parse::{Parse, ParseStream}, punctuated::Punctuated, - GenericArgument, Ident, Meta, Path, PathArguments, Token, Type, TypeParamBound, + Meta, Token, Type, }; pub(crate) struct TypeWithPunctuatedMeta { @@ -34,115 +32,6 @@ impl Parse for TypeWithPunctuatedMeta { } } -/// recursive (dereference, de_ptr, de_param) -#[inline] -pub(crate) fn find_idents_in_path<'a>( - set: &mut HashSet<&'a Ident>, - path: &'a Path, - recursive: Option<(bool, bool, bool)>, -) { - if let Some((_, _, de_param)) = recursive { - if de_param { - if let Some(segment) = path.segments.iter().last() { - if let PathArguments::AngleBracketed(a) = &segment.arguments { - // the ident is definitely not a generic parameter, so we don't insert it - - for arg in a.args.iter() { - match arg { - GenericArgument::Type(ty) => { - find_idents_in_type(set, ty, recursive); - }, - GenericArgument::AssocType(ty) => { - find_idents_in_type(set, &ty.ty, recursive); - }, - _ => (), - } - } - - return; - } - } - } - } - - if let Some(ty) = path.get_ident() { - set.insert(ty); - } -} - -/// recursive (dereference, de_ptr, de_param) -#[inline] -pub(crate) fn find_idents_in_type<'a>( - set: &mut HashSet<&'a Ident>, - ty: &'a Type, - recursive: Option<(bool, bool, bool)>, -) { - match ty { - Type::Array(ty) => { - if recursive.is_some() { - find_idents_in_type(set, ty.elem.as_ref(), recursive); - } - }, - Type::Group(ty) => { - if recursive.is_some() { - find_idents_in_type(set, ty.elem.as_ref(), recursive); - } - }, - Type::ImplTrait(ty) => { - // always recursive - for b in &ty.bounds { - if let TypeParamBound::Trait(ty) = b { - find_idents_in_path(set, &ty.path, recursive); - } - } - }, - Type::Macro(ty) => { - if recursive.is_some() { - find_idents_in_path(set, &ty.mac.path, recursive); - } - }, - Type::Paren(ty) => { - if recursive.is_some() { - find_idents_in_type(set, ty.elem.as_ref(), recursive); - } - }, - Type::Path(ty) => { - find_idents_in_path(set, &ty.path, recursive); - }, - Type::Ptr(ty) => { - if let Some((_, true, _)) = recursive { - find_idents_in_type(set, ty.elem.as_ref(), recursive); - } - }, - Type::Reference(ty) => { - if let Some((true, ..)) = recursive { - find_idents_in_type(set, ty.elem.as_ref(), recursive); - } - }, - Type::Slice(ty) => { - if recursive.is_some() { - find_idents_in_type(set, ty.elem.as_ref(), recursive); - } - }, - Type::TraitObject(ty) => { - // always recursive - for b in &ty.bounds { - if let TypeParamBound::Trait(ty) = b { - find_idents_in_path(set, &ty.path, recursive); - } - } - }, - Type::Tuple(ty) => { - if recursive.is_some() { - for ty in &ty.elems { - find_idents_in_type(set, ty, recursive) - } - } - }, - _ => (), - } -} - #[inline] pub(crate) fn dereference(ty: &Type) -> &Type { if let Type::Reference(ty) = ty { From ecaf0f229a7c083e28a410e9d8ee52109ae62592 Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 14:55:31 +0000 Subject: [PATCH 16/18] Abolish into_where_predicates_by_generic_parameters Nothing calls this. And, nothing should, because it would give wrong answers. Rename create_where_predicates_from_generic_parameters to create_where_predicates_from_all_generic_parameters. This will be useful if we implement a `bound(...)` syntax that allows requesting the "apply a bound for each generic parameter, regardless" mode. If we don't want to implement such a mode, we should delete this function, but let's not entangle this already large bugfix MR with questions about future features and UI. --- src/common/bound.rs | 14 -------------- src/common/where_predicates_bool.rs | 3 ++- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/src/common/bound.rs b/src/common/bound.rs index 3dac605..1ca85f2 100644 --- a/src/common/bound.rs +++ b/src/common/bound.rs @@ -1,7 +1,6 @@ use syn::{punctuated::Punctuated, token::Comma, GenericParam, Meta, Path, Type, WherePredicate}; use crate::common::where_predicates_bool::{ - create_where_predicates_from_generic_parameters, create_where_predicates_from_generic_parameters_check_types, meta_2_where_predicates, WherePredicates, WherePredicatesOrBool, }; @@ -33,19 +32,6 @@ impl Bound { } impl Bound { - #[inline] - pub(crate) fn into_where_predicates_by_generic_parameters( - self, - params: &Punctuated, - bound_trait: &Path, - ) -> Punctuated { - match self { - Self::Disabled => Punctuated::new(), - Self::Auto => create_where_predicates_from_generic_parameters(params, bound_trait), - Self::Custom(where_predicates) => where_predicates, - } - } - #[inline] pub(crate) fn into_where_predicates_by_generic_parameters_check_types( self, diff --git a/src/common/where_predicates_bool.rs b/src/common/where_predicates_bool.rs index f0b9464..359ebfa 100644 --- a/src/common/where_predicates_bool.rs +++ b/src/common/where_predicates_bool.rs @@ -87,7 +87,8 @@ pub(crate) fn meta_2_where_predicates(meta: &Meta) -> syn::Result, bound_trait: &Path, ) -> WherePredicates { From 7b9a95c6f234b027125b42b01c89496a124b879b Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 17:33:07 +0000 Subject: [PATCH 17/18] Ord: Fix build when PartialOrd is not enabled --- src/trait_handlers/ord/mod.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/trait_handlers/ord/mod.rs b/src/trait_handlers/ord/mod.rs index da9960d..ef6bb48 100644 --- a/src/trait_handlers/ord/mod.rs +++ b/src/trait_handlers/ord/mod.rs @@ -33,13 +33,17 @@ impl TraitHandler for OrdHandler { } } -fn supertraits(traits: &[Trait]) -> Vec { +fn supertraits( + #[allow(unused_variables)] + traits: &[Trait], +) -> Vec { let mut supertraits = vec![]; supertraits.push(quote! {::core::cmp::Eq}); // We mustn't add the PartialOrd bound to the educed PartialOrd impl. // When we're educing PartialOrd we can leave it off the Ord impl too, // since we *know* Self is going to be PartialOrd. + #[cfg(feature = "PartialOrd")] if !traits.contains(&Trait::PartialOrd) { supertraits.push(quote! {::core::cmp::PartialOrd}); }; From 4b07ecb344ec5c58e236fa68cf0d43dce4e7539c Mon Sep 17 00:00:00 2001 From: Ian Jackson Date: Tue, 20 Feb 2024 18:03:18 +0000 Subject: [PATCH 18/18] Ord: Fix build when PartialOrd is not enabled (rustfmt) --- src/trait_handlers/ord/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/trait_handlers/ord/mod.rs b/src/trait_handlers/ord/mod.rs index ef6bb48..2b37631 100644 --- a/src/trait_handlers/ord/mod.rs +++ b/src/trait_handlers/ord/mod.rs @@ -33,10 +33,7 @@ impl TraitHandler for OrdHandler { } } -fn supertraits( - #[allow(unused_variables)] - traits: &[Trait], -) -> Vec { +fn supertraits(#[allow(unused_variables)] traits: &[Trait]) -> Vec { let mut supertraits = vec![]; supertraits.push(quote! {::core::cmp::Eq});