diff --git a/CHANGELOG.md b/CHANGELOG.md index 038d7e488f5..53e113224a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,8 @@ - `yoke` - Remove `StableDeref` bound from `Yoke>` methods (https://github.com/unicode-org/icu4x/pull/4457) - Added `CartableOptionPointer` and function to convert from `Yoke>` (https://github.com/unicode-org/icu4x/pull/4449)\ + - `zerofrom` + - Support `?Sized` type parameters which must be `Sized` to implement `ZeroFrom` (https://github.com/unicode-org/icu4x/pull/4657) - `zerotrie` - Add `as_borrowed_slice` and `AsRef` impl (https://github.com/unicode-org/icu4x/pull/4381) - Add `ZeroTrieSimpleAsciiCursor` for manual iteration (https://github.com/unicode-org/icu4x/pull/4383) diff --git a/utils/zerofrom/derive/examples/zf_derive.rs b/utils/zerofrom/derive/examples/zf_derive.rs index a1bde83733c..d3eb2a6fb65 100644 --- a/utils/zerofrom/derive/examples/zf_derive.rs +++ b/utils/zerofrom/derive/examples/zf_derive.rs @@ -4,7 +4,7 @@ #![allow(unused)] -use std::borrow::Cow; +use std::{borrow::Cow, marker::PhantomData}; use zerofrom::ZeroFrom; use zerovec::{maps::ZeroMapKV, ule::AsULE, VarZeroVec, ZeroMap, ZeroVec}; @@ -87,27 +87,29 @@ pub enum CloningZF3<'data> { } #[derive(ZeroFrom)] -#[zerofrom(may_borrow(T))] // instead of treating T as a copy type, we want to allow zerofromming T too -pub struct GenericsThatAreAlsoZf { +#[zerofrom(may_borrow(T, Q))] // instead of treating T as a copy type, we want to allow zerofromming T too +pub struct GenericsThatAreAlsoZf { x: T, y: Option, + ignored: PhantomData, + q: Q, } pub fn assert_zf_generics_may_borrow<'a, 'b>( - x: &'b GenericsThatAreAlsoZf<&'a str>, -) -> GenericsThatAreAlsoZf<&'b str> { - GenericsThatAreAlsoZf::<&'b str>::zero_from(x) + x: &'b GenericsThatAreAlsoZf<&'a str, usize, str>, +) -> GenericsThatAreAlsoZf<&'b str, usize, str> { + GenericsThatAreAlsoZf::<&'b str, usize, str>::zero_from(x) } #[derive(ZeroFrom)] pub struct UsesGenericsThatAreAlsoZf<'a> { - x: GenericsThatAreAlsoZf<&'a str>, + x: GenericsThatAreAlsoZf<&'a str, usize, str>, } // Ensure it works with invariant types too #[derive(ZeroFrom)] pub struct UsesGenericsThatAreAlsoZfWithMap<'a> { - x: GenericsThatAreAlsoZf>, + x: GenericsThatAreAlsoZf, usize, str>, } fn main() {} diff --git a/utils/zerofrom/derive/src/lib.rs b/utils/zerofrom/derive/src/lib.rs index c6a3839fb5d..bb48ec26efe 100644 --- a/utils/zerofrom/derive/src/lib.rs +++ b/utils/zerofrom/derive/src/lib.rs @@ -27,8 +27,8 @@ use syn::fold::{self, Fold}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - parse_macro_input, parse_quote, DeriveInput, Ident, Lifetime, MetaList, Token, Type, TypePath, - WherePredicate, + parse_macro_input, parse_quote, DeriveInput, Ident, Lifetime, MetaList, Token, + TraitBoundModifier, Type, TypeParamBound, TypePath, WherePredicate, }; use synstructure::Structure; mod visitor; @@ -121,12 +121,26 @@ fn zf_derive_impl(input: &DeriveInput) -> TokenStream2 { // a newly introduced mirror type parameter that we are borrowing from, similar to C in the original trait. // For convenience, we are calling these "C types" let generics_env: HashMap> = tybounds - .iter() + .iter_mut() .map(|param| { // First one doesn't work yet https://github.com/rust-lang/rust/issues/114393 let maybe_new_param = if has_attr(¶m.attrs, "may_borrow") || may_borrow_attrs.contains(¶m.ident) { + // Remove `?Sized`` bound because we need a param to be Sized in order to take a ZeroFrom of it. + // This only applies to fields marked as `may_borrow`. + let mut bounds = core::mem::take(&mut param.bounds); + while let Some(bound_pair) = bounds.pop() { + let bound = bound_pair.into_value(); + if let TypeParamBound::Trait(ref trait_bound) = bound { + if trait_bound.path.get_ident().map(|ident| ident == "Sized") == Some(true) + && matches!(trait_bound.modifier, TraitBoundModifier::Maybe(_)) + { + continue; + } + } + param.bounds.push(bound); + } Some(Ident::new( &format!("{}ZFParamC", param.ident), param.ident.span(), diff --git a/utils/zerofrom/src/zero_from.rs b/utils/zerofrom/src/zero_from.rs index 204b3b635cd..626cfc9f871 100644 --- a/utils/zerofrom/src/zero_from.rs +++ b/utils/zerofrom/src/zero_from.rs @@ -2,6 +2,8 @@ // called LICENSE at the top level of the ICU4X source tree // (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ). +use core::marker::PhantomData; + #[cfg(feature = "alloc")] use alloc::borrow::{Cow, ToOwned}; #[cfg(feature = "alloc")] @@ -126,3 +128,9 @@ impl<'zf, T> ZeroFrom<'zf, [T]> for &'zf [T] { other } } + +impl<'zf, T: ?Sized + 'zf> ZeroFrom<'zf, PhantomData> for PhantomData { + fn zero_from(other: &'zf PhantomData) -> Self { + *other + } +}