From 1e97c79ec1149c275da8f0196fd20b07ff501d8c Mon Sep 17 00:00:00 2001 From: Jamie Ridding Date: Mon, 5 Jun 2023 23:47:08 +0100 Subject: [PATCH] bevy_reflect: Disambiguate type bounds in where clauses. (#8761) # Objective 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 field types in a type's definition to its `where` clauses made it very easy to accidentally run into this behaviour - particularly with the construct ```rust where for<'a> fn(&'a T) -> &'a T: Trait1 + Trait2 ``` which was incorrectly parsed as ```rust where for<'a> (fn(&'a T) -> &'a T: Trait1 + Trait2) ^ ^ incorrect syntax grouping ``` instead of ```rust where (for<'a> fn(&'a T) -> &'a T): Trait1 + Trait2 ^ ^ correct syntax grouping ``` Fixes #8759 ## Solution This commit fixes the issue by inserting explicit parentheses to disambiguate types from their bound lists. --- .../bevy_reflect_derive/src/utility.rs | 11 +++++++--- crates/bevy_reflect/src/lib.rs | 20 +++++++++++++++++++ 2 files changed, 28 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 b8efa3f530..32549bd4af 100644 --- a/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs +++ b/crates/bevy_reflect/bevy_reflect_derive/src/utility.rs @@ -155,11 +155,16 @@ 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,)* + #((#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 } diff --git a/crates/bevy_reflect/src/lib.rs b/crates/bevy_reflect/src/lib.rs index c00b91e626..1322142796 100644 --- a/crates/bevy_reflect/src/lib.rs +++ b/crates/bevy_reflect/src/lib.rs @@ -1426,6 +1426,26 @@ 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();