Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue with specific reflect breaking after upgrading from 0.9-0.10 #7989

Closed
CoffeeVampir3 opened this issue Mar 9, 2023 · 3 comments · Fixed by #8014
Closed

Issue with specific reflect breaking after upgrading from 0.9-0.10 #7989

CoffeeVampir3 opened this issue Mar 9, 2023 · 3 comments · Fixed by #8014
Labels
A-Reflection Runtime information about types C-Bug An unexpected or incorrect behavior
Milestone

Comments

@CoffeeVampir3
Copy link

CoffeeVampir3 commented Mar 9, 2023

Bevy 0.10

0.10

What you did

Upgraded from bevy 0.9 -> 0.10

What went wrong

The following code has stopped compiling:

use bevy::{reflect::Reflect, utils::HashSet};

#[derive(Default, Clone, Reflect, serde::Serialize, serde::Deserialize)]
pub struct NetSet<T> where T: 'static + Send + Sync + Eq + Copy + core::hash::Hash {
    set: HashSet<T>
}

There's an error for the reflect derive,

Proc-macro derive produced unparseable tokens

and one for the HashSet

expected one of `(`, `+`, `,`, `::`, `<`, or `{`, found `HashSet`
unexpected token ...

Additional information

Full 0.9 version: https://github.com/CoffeeVampir3/rusty_cg/blob/main/src/structures/netset.rs

image
image

Fully expanded proc macro:

// Recursive expansion of Reflect! macro
// ======================================

#[allow(unused_mut)]
impl <T>bevy::reflect::GetTypeRegistration for NetSet<T>where T:'static+Send+Sync+Eq+Copy+core::hash::Hash HashSet<T> :bevy::reflect::Reflect,{
  fn get_type_registration() -> bevy::reflect::TypeRegistration {
    let mut registration = bevy::reflect::TypeRegistration::of:: <NetSet<T> >();
    registration.insert:: <bevy::reflect::ReflectFromPtr>(bevy::reflect::FromType:: <NetSet<T> > ::from_type());
    let ignored_indices =  ::core::iter::IntoIterator::into_iter([]);
    registration.insert:: <bevy::reflect::serde::SerializationData>(bevy::reflect::serde::SerializationData::new(ignored_indices));
    registration
  }

  }
impl <T>bevy::reflect::Typed for NetSet<T>where T:'static+Send+Sync+Eq+Copy+core::hash::Hash HashSet<T> :bevy::reflect::Reflect,{
  fn type_info() ->  &'static bevy::reflect::TypeInfo {
    static CELL:bevy::reflect::utility::GenericTypeInfoCell = bevy::reflect::utility::GenericTypeInfoCell::new();
    CELL.get_or_insert:: <Self,_>(||{
      let fields = [bevy::reflect::NamedField::new:: <HashSet<T> >("set"),];
      let info = bevy::reflect::StructInfo::new:: <Self>("NetSet", &fields);
      bevy::reflect::TypeInfo::Struct(info)
    })
  }

  }
impl <T>bevy::reflect::Struct for NetSet<T>where T:'static+Send+Sync+Eq+Copy+core::hash::Hash HashSet<T> :bevy::reflect::Reflect,{
  fn field(&self,name: &str) ->  ::core::option::Option< &dyn bevy::reflect::Reflect>{
    match name {
      "set" =>  ::core::option::Option::Some(&self.set),
      _ =>  ::core::option::Option::None,
    
      }
  }
  fn field_mut(&mut self,name: &str) ->  ::core::option::Option< &mut dyn bevy::reflect::Reflect>{
    match name {
      "set" =>  ::core::option::Option::Some(&mut self.set),
      _ =>  ::core::option::Option::None,
    
      }
  }
  fn field_at(&self,index:usize) ->  ::core::option::Option< &dyn bevy::reflect::Reflect>{
    match index {
      0usize =>  ::core::option::Option::Some(&self.set),
      _ =>  ::core::option::Option::None,
    
      }
  }
  fn field_at_mut(&mut self,index:usize) ->  ::core::option::Option< &mut dyn bevy::reflect::Reflect>{
    match index {
      0usize =>  ::core::option::Option::Some(&mut self.set),
      _ =>  ::core::option::Option::None,
    
      }
  }
  fn name_at(&self,index:usize) ->  ::core::option::Option< &str>{
    match index {
      0usize =>  ::core::option::Option::Some("set"),
      _ =>  ::core::option::Option::None,
    
      }
  }
  fn field_len(&self) -> usize {
    1usize
  }
  fn iter_fields(&self) -> bevy::reflect::FieldIter {
    bevy::reflect::FieldIter::new(self)
  }
  fn clone_dynamic(&self) -> bevy::reflect::DynamicStruct {
    let mut dynamic:bevy::reflect::DynamicStruct =  ::core::default::Default::default();
    dynamic.set_name(::std::string::ToString::to_string(bevy::reflect::Reflect::type_name(self)));
    dynamic.insert_boxed("set",bevy::reflect::Reflect::clone_value(&self.set));
    dynamic
  }

  }
impl <T>bevy::reflect::Reflect for NetSet<T>where T:'static+Send+Sync+Eq+Copy+core::hash::Hash HashSet<T> :bevy::reflect::Reflect,{
  #[inline]
  fn type_name(&self) ->  &str {
    ::core::any::type_name:: <Self>()
  }
  #[inline]
  fn get_type_info(&self) ->  &'static bevy::reflect::TypeInfo {
    <Self as bevy::reflect::Typed> ::type_info()
  }
  #[inline]
  fn into_any(self: ::std::boxed::Box<Self>) ->  ::std::boxed::Box<dyn ::core::any::Any>{
    self
  }
  #[inline]
  fn as_any(&self) ->  &dyn ::core::any::Any {
    self
  }
  #[inline]
  fn as_any_mut(&mut self) ->  &mut dyn ::core::any::Any {
    self
  }
  #[inline]
  fn into_reflect(self: ::std::boxed::Box<Self>) ->  ::std::boxed::Box<dyn bevy::reflect::Reflect>{
    self
  }
  #[inline]
  fn as_reflect(&self) ->  &dyn bevy::reflect::Reflect {
    self
  }
  #[inline]
  fn as_reflect_mut(&mut self) ->  &mut dyn bevy::reflect::Reflect {
    self
  }
  #[inline]
  fn clone_value(&self) ->  ::std::boxed::Box<dyn bevy::reflect::Reflect>{
    ::std::boxed::Box::new(bevy::reflect::Struct::clone_dynamic(self))
  }
  #[inline]
  fn set(&mut self,value: ::std::boxed::Box<dyn bevy::reflect::Reflect>) ->  ::core::result::Result<(), ::std::boxed::Box<dyn bevy::reflect::Reflect>>{
    *self =  <dyn bevy::reflect::Reflect> ::take(value)? ;
    ::core::result::Result::Ok(())
  }
  #[inline]
  fn apply(&mut self,value: &dyn bevy::reflect::Reflect){
    if let bevy::reflect::ReflectRef::Struct(struct_value) = bevy::reflect::Reflect::reflect_ref(value){
      for(i,value)in::core::iter::Iterator::enumerate(bevy::reflect::Struct::iter_fields(struct_value)){
        let name = bevy::reflect::Struct::name_at(struct_value,i).unwrap();
        bevy::reflect::Struct::field_mut(self,name).map(|v|v.apply(value));
      }
    }else {
      panic!("Attempted to apply non-struct type to struct type.");
    }
  }
  fn reflect_ref(&self) -> bevy::reflect::ReflectRef {
    bevy::reflect::ReflectRef::Struct(self)
  }
  fn reflect_mut(&mut self) -> bevy::reflect::ReflectMut {
    bevy::reflect::ReflectMut::Struct(self)
  }
  fn reflect_owned(self: ::std::boxed::Box<Self>) -> bevy::reflect::ReflectOwned {
    bevy::reflect::ReflectOwned::Struct(self)
  }
  fn reflect_partial_eq(&self,value: &dyn bevy::reflect::Reflect) ->  ::core::option::Option<bool>{
    bevy::reflect::struct_partial_eq(self,value)
  }

  }
@CoffeeVampir3 CoffeeVampir3 added C-Bug An unexpected or incorrect behavior S-Needs-Triage This issue needs to be labelled labels Mar 9, 2023
@CoffeeVampir3
Copy link
Author

After expanding the macro I think I've found the issue:

The emitted version of the macro (one example)

#[allow(unused_mut)]
impl <T>bevy::reflect::GetTypeRegistration for NetSet<T>where T:'static+Send+Sync+Eq+Copy+core::hash::Hash HashSet<T> :bevy::reflect::Reflect,{
  fn get_type_registration() -> bevy::reflect::TypeRegistration {
    let mut registration = bevy::reflect::TypeRegistration::of:: <NetSet<T> >();
    registration.insert:: <bevy::reflect::ReflectFromPtr>(bevy::reflect::FromType:: <NetSet<T> > ::from_type());
    let ignored_indices =  ::core::iter::IntoIterator::into_iter([]);
    registration.insert:: <bevy::reflect::serde::SerializationData>(bevy::reflect::serde::SerializationData::new(ignored_indices));
    registration
  }

there's a missing comma on the reflect emit it appears. gunna dig into the reflect proc macro and see if I can get it to work.

@JMS55 JMS55 added A-Reflection Runtime information about types and removed S-Needs-Triage This issue needs to be labelled labels Mar 9, 2023
@JMS55 JMS55 added this to the 0.10.1 milestone Mar 9, 2023
@MrGVSV
Copy link
Member

MrGVSV commented Mar 10, 2023

Closing in favor of #8014

@MrGVSV MrGVSV closed this as not planned Won't fix, can't repro, duplicate, stale Mar 10, 2023
@MrGVSV
Copy link
Member

MrGVSV commented Mar 10, 2023

Lol closed the issue instead of the PR 🤦‍♂️

@MrGVSV MrGVSV reopened this Mar 10, 2023
@cart cart closed this as completed in 5e5a305 Mar 27, 2023
mockersf pushed a commit that referenced this issue Mar 27, 2023
# 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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Reflection Runtime information about types C-Bug An unexpected or incorrect behavior
Projects
Status: Done
3 participants