-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bevy_reflect: Fix trailing comma breaking derives (#8014)
# Objective Fixes #7989 Based on #7991 by @CoffeeVampir3 ## Solution There were three parts to this issue: 1. `extend_where_clause` did not account for the optionality of a where clause's trailing comma ```rust // OKAY struct Foo<T> where T: Asset, {/* ... */} // ERROR struct Foo<T> where T: Asset {/* ... */} ``` 2. `FromReflect` derive logic was not actively using `extend_where_clause` which led to some inconsistencies (enums weren't adding _any_ additional bounds even) 3. Using `extend_where_clause` in the `FromReflect` derive logic meant we had to optionally add `Default` bounds to ignored fields iff the entire item itself was not already `Default` (otherwise the definition for `Handle<T>` wouldn't compile since `HandleType` doesn't impl `Default` but `Handle<T>` itself does) --- ## Changelog - Fixed issue where a missing trailing comma could break the reflection derives
- Loading branch information
Showing
3 changed files
with
314 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
282 changes: 282 additions & 0 deletions
282
crates/bevy_reflect_compile_fail_tests/tests/reflect_derive/bounds.pass.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,282 @@ | ||
use bevy_reflect::prelude::*; | ||
|
||
fn main() {} | ||
|
||
#[derive(Default)] | ||
struct NonReflect; | ||
|
||
struct NonReflectNonDefault; | ||
|
||
mod structs { | ||
use super::*; | ||
|
||
#[derive(Reflect)] | ||
struct ReflectGeneric<T> { | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
struct FromReflectGeneric<T> { | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[reflect(Default)] | ||
struct DefaultGeneric<T> { | ||
foo: Option<T>, | ||
#[reflect(ignore)] | ||
_ignored: NonReflectNonDefault, | ||
} | ||
|
||
impl<T> Default for DefaultGeneric<T> { | ||
fn default() -> Self { | ||
Self { | ||
foo: None, | ||
_ignored: NonReflectNonDefault, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Reflect)] | ||
struct ReflectBoundGeneric<T: Clone> { | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
struct FromReflectBoundGeneric<T: Clone> { | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[reflect(Default)] | ||
struct DefaultBoundGeneric<T: Clone> { | ||
foo: Option<T>, | ||
#[reflect(ignore)] | ||
_ignored: NonReflectNonDefault, | ||
} | ||
|
||
impl<T: Clone> Default for DefaultBoundGeneric<T> { | ||
fn default() -> Self { | ||
Self { | ||
foo: None, | ||
_ignored: NonReflectNonDefault, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Reflect)] | ||
struct ReflectGenericWithWhere<T> | ||
where | ||
T: Clone, | ||
{ | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
struct FromReflectGenericWithWhere<T> | ||
where | ||
T: Clone, | ||
{ | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[reflect(Default)] | ||
struct DefaultGenericWithWhere<T> | ||
where | ||
T: Clone, | ||
{ | ||
foo: Option<T>, | ||
#[reflect(ignore)] | ||
_ignored: NonReflectNonDefault, | ||
} | ||
|
||
impl<T> Default for DefaultGenericWithWhere<T> | ||
where | ||
T: Clone, | ||
{ | ||
fn default() -> Self { | ||
Self { | ||
foo: None, | ||
_ignored: NonReflectNonDefault, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Reflect)] | ||
#[rustfmt::skip] | ||
struct ReflectGenericWithWhereNoTrailingComma<T> | ||
where | ||
T: Clone | ||
{ | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[rustfmt::skip] | ||
struct FromReflectGenericWithWhereNoTrailingComma<T> | ||
where | ||
T: Clone | ||
{ | ||
foo: T, | ||
#[reflect(ignore)] | ||
_ignored: NonReflect, | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[reflect(Default)] | ||
#[rustfmt::skip] | ||
struct DefaultGenericWithWhereNoTrailingComma<T> | ||
where | ||
T: Clone | ||
{ | ||
foo: Option<T>, | ||
#[reflect(ignore)] | ||
_ignored: NonReflectNonDefault, | ||
} | ||
|
||
impl<T> Default for DefaultGenericWithWhereNoTrailingComma<T> | ||
where | ||
T: Clone, | ||
{ | ||
fn default() -> Self { | ||
Self { | ||
foo: None, | ||
_ignored: NonReflectNonDefault, | ||
} | ||
} | ||
} | ||
} | ||
|
||
mod tuple_structs { | ||
use super::*; | ||
|
||
#[derive(Reflect)] | ||
struct ReflectGeneric<T>(T, #[reflect(ignore)] NonReflect); | ||
|
||
#[derive(Reflect, FromReflect)] | ||
struct FromReflectGeneric<T>(T, #[reflect(ignore)] NonReflect); | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[reflect(Default)] | ||
struct DefaultGeneric<T>(Option<T>, #[reflect(ignore)] NonReflectNonDefault); | ||
|
||
impl<T> Default for DefaultGeneric<T> { | ||
fn default() -> Self { | ||
Self(None, NonReflectNonDefault) | ||
} | ||
} | ||
|
||
#[derive(Reflect)] | ||
struct ReflectBoundGeneric<T: Clone>(T, #[reflect(ignore)] NonReflect); | ||
|
||
#[derive(Reflect, FromReflect)] | ||
struct FromReflectBoundGeneric<T: Clone>(T, #[reflect(ignore)] NonReflect); | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[reflect(Default)] | ||
struct DefaultBoundGeneric<T: Clone>(Option<T>, #[reflect(ignore)] NonReflectNonDefault); | ||
|
||
impl<T: Clone> Default for DefaultBoundGeneric<T> { | ||
fn default() -> Self { | ||
Self(None, NonReflectNonDefault) | ||
} | ||
} | ||
|
||
#[derive(Reflect)] | ||
struct ReflectGenericWithWhere<T>(T, #[reflect(ignore)] NonReflect) | ||
where | ||
T: Clone; | ||
|
||
#[derive(Reflect, FromReflect)] | ||
struct FromReflectGenericWithWhere<T>(T, #[reflect(ignore)] NonReflect) | ||
where | ||
T: Clone; | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[reflect(Default)] | ||
struct DefaultGenericWithWhere<T>(Option<T>, #[reflect(ignore)] NonReflectNonDefault) | ||
where | ||
T: Clone; | ||
|
||
impl<T> Default for DefaultGenericWithWhere<T> | ||
where | ||
T: Clone, | ||
{ | ||
fn default() -> Self { | ||
Self(None, NonReflectNonDefault) | ||
} | ||
} | ||
} | ||
|
||
mod enums { | ||
use super::*; | ||
|
||
#[derive(Reflect)] | ||
enum ReflectGeneric<T> { | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
enum FromReflectGeneric<T> { | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
|
||
#[derive(Reflect)] | ||
enum ReflectBoundGeneric<T: Clone> { | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
enum FromReflectBoundGeneric<T: Clone> { | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
|
||
#[derive(Reflect)] | ||
enum ReflectGenericWithWhere<T> | ||
where | ||
T: Clone, | ||
{ | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
enum FromReflectGenericWithWhere<T> | ||
where | ||
T: Clone, | ||
{ | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
|
||
#[derive(Reflect)] | ||
#[rustfmt::skip] | ||
enum ReflectGenericWithWhereNoTrailingComma<T> | ||
where | ||
T: Clone | ||
{ | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
|
||
#[derive(Reflect, FromReflect)] | ||
#[rustfmt::skip] | ||
enum FromReflectGenericWithWhereNoTrailingComma<T> | ||
where | ||
T: Clone | ||
{ | ||
Foo(T, #[reflect(ignore)] NonReflect), | ||
} | ||
} |