From c6c5fbe196994f4c6bdc2fee93cee4f2907cc1b1 Mon Sep 17 00:00:00 2001 From: Jamie Ridding Date: Mon, 5 Jun 2023 22:01:03 +0100 Subject: [PATCH 1/4] bevy_reflect: Disambiguate type bounds in where clauses. It was accidentally found that rustc is unable to parse certain constructs in `where` clauses properly. bevy_reflect::Reflect's habit of copying and pasting the types in a struct's definition to its where clauses made it very easy to accidentally run into this behaviour - particularly with the construct for<'a> fn(&'a T) -> &'a T: Trait1 + Trait2 which was incorrectly parsed as for<'a> (fn(&'a T) -> &'a T: Trait1 + Trait2) instead of (for<'a> fn(&'a T) -> &'a T): Trait1 + Trait2 This commit fixes the issue by inserting explicit parentheses to disambiguate types from their bound lists. --- crates/bevy_reflect/bevy_reflect_derive/src/utility.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs b/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs index b8efa3f530e62..71da5ac238f75 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs @@ -156,10 +156,10 @@ pub(crate) fn extend_where_clause( quote!() }; generic_where_clause.extend(quote! { - #(#active_types: #active_trait_bounds,)* - #(#ignored_types: #ignored_trait_bounds,)* + #((#active_types): #active_trait_bounds,)* + #((#ignored_types): #ignored_trait_bounds,)* // Leave parameter bounds to the end for more sane error messages. - #(#parameter_types: #parameter_trait_bounds,)* + #((#parameter_types): #parameter_trait_bounds,)* }); generic_where_clause } From 9ca8fc841afe1a1d6b701e071a2a8d824daaedca Mon Sep 17 00:00:00 2001 From: Jamie Ridding Date: Mon, 5 Jun 2023 22:20:32 +0100 Subject: [PATCH 2/4] Add regression test for Reflect hrl fix --- crates/bevy_reflect/src/lib.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index c00b91e626ff1..22bfad5d0d819 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -1426,6 +1426,24 @@ mod tests { assert!(info.is::()); } + #[test] + fn should_permit_higher_ranked_lifetimes() { + #[derive(Reflect)] + struct TestStruct { + #[reflect(ignore)] + _hrl: for<'a> fn(&'a str) -> &'a str, + } + + impl Default for TestStruct { + fn default() -> Self { + TestStruct { _hrl: |input| input } + } + } + + fn get_type_registration() { } + get_type_registration::(); + } + #[test] fn should_permit_valid_represented_type_for_dynamic() { let type_info = <[i32; 2] as Typed>::type_info(); From 001a82a7f968a9065ce3c232d7bd477869c9f06f Mon Sep 17 00:00:00 2001 From: Jamie Ridding Date: Mon, 5 Jun 2023 22:39:41 +0100 Subject: [PATCH 3/4] Reformatting --- crates/bevy_reflect/src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index 22bfad5d0d819..13221427960d9 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -1436,11 +1436,13 @@ mod tests { impl Default for TestStruct { fn default() -> Self { - TestStruct { _hrl: |input| input } + TestStruct { + _hrl: |input| input, + } } } - fn get_type_registration() { } + fn get_type_registration() {} get_type_registration::(); } From ebbab1ed4e89655937e66fc1233c93fc61def9ef Mon Sep 17 00:00:00 2001 From: Jamie Ridding Date: Mon, 5 Jun 2023 23:25:43 +0100 Subject: [PATCH 4/4] Add a comment explaining the reason for seemingly spurious parentheses. --- crates/bevy_reflect/bevy_reflect_derive/src/utility.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs b/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs index 71da5ac238f75..32549bd4af8e3 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs @@ -155,6 +155,11 @@ pub(crate) fn extend_where_clause( } else { quote!() }; + + // The nested parentheses here are required to properly scope HRTBs coming + // from field types to the type itself, as the compiler will scope them to + // the whole bound by default, resulting in a failure to prove trait + // adherence. generic_where_clause.extend(quote! { #((#active_types): #active_trait_bounds,)* #((#ignored_types): #ignored_trait_bounds,)*