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.
This commit is contained in:
Jamie Ridding 2023-06-05 23:47:08 +01:00 committed by GitHub
parent b72b15465d
commit 1e97c79ec1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 3 deletions

View file

@ -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
}

View file

@ -1426,6 +1426,26 @@ mod tests {
assert!(info.is::<MyValue>());
}
#[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<T: GetTypeRegistration>() {}
get_type_registration::<TestStruct>();
}
#[test]
fn should_permit_valid_represented_type_for_dynamic() {
let type_info = <[i32; 2] as Typed>::type_info();