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

[Merged by Bors] - Make proc macros hygienic in bevy_reflect_derive #6752

Closed
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions crates/bevy_reflect/bevy_reflect_derive/src/container_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

use crate::utility;
use proc_macro2::{Ident, Span};
use quote::quote_spanned;
use quote::{quote, quote_spanned};
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::spanned::Spanned;
Expand Down Expand Up @@ -220,19 +220,22 @@ impl ReflectTraits {
///
/// If `Hash` was not registered, returns `None`.
pub fn get_hash_impl(&self, bevy_reflect_path: &Path) -> Option<proc_macro2::TokenStream> {
let option = quote!(::core::option::Option);
let any = quote!(::core::any::Any);
elbertronnie marked this conversation as resolved.
Show resolved Hide resolved

match &self.hash {
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
fn reflect_hash(&self) -> Option<u64> {
use std::hash::{Hash, Hasher};
let mut hasher = #bevy_reflect_path::ReflectHasher::default();
Hash::hash(&std::any::Any::type_id(self), &mut hasher);
fn reflect_hash(&self) -> #option<u64> {
use ::core::hash::{Hash, Hasher};
let mut hasher: #bevy_reflect_path::ReflectHasher = ::core::default::Default::default();
Hash::hash(&#any::type_id(self), &mut hasher);
Hash::hash(self, &mut hasher);
Some(hasher.finish())
#option::Some(Hasher::finish(&hasher))
}
}),
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
fn reflect_hash(&self) -> Option<u64> {
Some(#impl_fn(self))
fn reflect_hash(&self) -> #option<u64> {
#option::Some(#impl_fn(self))
}
}),
TraitImpl::NotImplemented => None,
Expand All @@ -246,20 +249,23 @@ impl ReflectTraits {
&self,
bevy_reflect_path: &Path,
) -> Option<proc_macro2::TokenStream> {
let option = quote!(::core::option::Option);
let any = quote!(::core::any::Any);

match &self.partial_eq {
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option<bool> {
let value = value.as_any();
if let Some(value) = value.downcast_ref::<Self>() {
Some(std::cmp::PartialEq::eq(self, value))
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> #option<bool> {
let value = <dyn #bevy_reflect_path::Reflect>::as_any(value);
if let #option::Some(value) = <dyn #any>::downcast_ref::<Self>(value) {
#option::Some(::core::cmp::PartialEq::eq(self, value))
} else {
Some(false)
#option::Some(false)
}
}
}),
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> Option<bool> {
Some(#impl_fn(self, value))
fn reflect_partial_eq(&self, value: &dyn #bevy_reflect_path::Reflect) -> #option<bool> {
#option::Some(#impl_fn(self, value))
}
}),
TraitImpl::NotImplemented => None,
Expand All @@ -272,12 +278,12 @@ impl ReflectTraits {
pub fn get_debug_impl(&self) -> Option<proc_macro2::TokenStream> {
match &self.debug {
&TraitImpl::Implemented(span) => Some(quote_spanned! {span=>
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self, f)
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
::core::fmt::Debug::fmt(self, f)
}
}),
&TraitImpl::Custom(ref impl_fn, span) => Some(quote_spanned! {span=>
fn debug(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
fn debug(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
#impl_fn(self, f)
}
}),
Expand Down
5 changes: 3 additions & 2 deletions crates/bevy_reflect/bevy_reflect_derive/src/documentation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ impl Documentation {

impl ToTokens for Documentation {
fn to_tokens(&self, tokens: &mut TokenStream) {
let option = quote!(::core::option::Option);
if let Some(doc) = self.doc_string() {
quote!(Some(#doc)).to_tokens(tokens);
quote!(#option::Some(#doc)).to_tokens(tokens);
} else {
quote!(None).to_tokens(tokens);
quote!(#option::None).to_tokens(tokens);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ pub(crate) fn get_variant_constructors(
let constructor_fields = fields.iter().enumerate().map(|(declar_index, field)| {
let field_ident = ident_or_index(field.data.ident.as_ref(), declar_index);
let field_value = if field.attrs.ignore.is_ignored() {
quote! { Default::default() }
quote! { ::core::default::Default::default() }
} else {
let error_repr = field.data.ident.as_ref().map_or_else(
|| format!("at index {reflect_index}"),
Expand Down
50 changes: 30 additions & 20 deletions crates/bevy_reflect/bevy_reflect_derive/src/from_reflect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,26 @@ pub(crate) fn impl_tuple_struct(reflect_struct: &ReflectStruct) -> TokenStream {

/// Implements `FromReflect` for the given value type
pub(crate) fn impl_value(meta: &ReflectMeta) -> TokenStream {
let option = quote!(::core::option::Option);
elbertronnie marked this conversation as resolved.
Show resolved Hide resolved
let clone = quote!(::core::clone::Clone::clone);
let any = quote!(::core::any::Any);

let type_name = meta.type_name();
let bevy_reflect_path = meta.bevy_reflect_path();
let (impl_generics, ty_generics, where_clause) = meta.generics().split_for_impl();
TokenStream::from(quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #type_name #ty_generics #where_clause {
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> Option<Self> {
Some(reflect.as_any().downcast_ref::<#type_name #ty_generics>()?.clone())
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #option<Self> {
#option::Some(#clone(<dyn #any>::downcast_ref::<#type_name #ty_generics>(<dyn #bevy_reflect_path::Reflect>::as_any(reflect))?))
}
}
})
}

/// Implements `FromReflect` for the given enum type
pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
let option = quote!(::core::option::Option);

let type_name = reflect_enum.meta().type_name();
let bevy_reflect_path = reflect_enum.meta().bevy_reflect_path();

Expand All @@ -47,14 +53,14 @@ pub(crate) fn impl_enum(reflect_enum: &ReflectEnum) -> TokenStream {
reflect_enum.meta().generics().split_for_impl();
TokenStream::from(quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #type_name #ty_generics #where_clause {
fn from_reflect(#ref_value: &dyn #bevy_reflect_path::Reflect) -> Option<Self> {
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #ref_value.reflect_ref() {
match #ref_value.variant_name() {
#(#variant_names => Some(#variant_constructors),)*
name => panic!("variant with name `{}` does not exist on enum `{}`", name, std::any::type_name::<Self>()),
fn from_reflect(#ref_value: &dyn #bevy_reflect_path::Reflect) -> #option<Self> {
if let #bevy_reflect_path::ReflectRef::Enum(#ref_value) = #bevy_reflect_path::Reflect::reflect_ref(#ref_value) {
match #bevy_reflect_path::Enum::variant_name(#ref_value) {
#(#variant_names => #option::Some(#variant_constructors),)*
name => panic!("variant with name `{}` does not exist on enum `{}`", name, ::core::any::type_name::<Self>()),
}
} else {
None
#option::None
}
}
}
Expand All @@ -72,6 +78,8 @@ impl MemberValuePair {
}

fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> TokenStream {
let option = quote!(::core::option::Option);

let struct_name = reflect_struct.meta().type_name();
let generics = reflect_struct.meta().generics();
let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();
Expand All @@ -89,21 +97,21 @@ fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> Token

let constructor = if reflect_struct.meta().traits().contains(REFLECT_DEFAULT) {
quote!(
let mut __this = Self::default();
let mut __this: Self = ::core::default::Default::default();
#(
if let Some(__field) = #active_values() {
if let #option::Some(__field) = #active_values() {
// Iff field exists -> use its value
__this.#active_members = __field;
}
)*
Some(__this)
#option::Some(__this)
)
} else {
let MemberValuePair(ignored_members, ignored_values) =
get_ignored_fields(reflect_struct, is_tuple);

quote!(
Some(
#option::Some(
Self {
#(#active_members: #active_values()?,)*
#(#ignored_members: #ignored_values,)*
Expand All @@ -129,11 +137,11 @@ fn impl_struct_internal(reflect_struct: &ReflectStruct, is_tuple: bool) -> Token
TokenStream::from(quote! {
impl #impl_generics #bevy_reflect_path::FromReflect for #struct_name #ty_generics #where_from_reflect_clause
{
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> Option<Self> {
if let #bevy_reflect_path::ReflectRef::#ref_struct_type(#ref_struct) = reflect.reflect_ref() {
fn from_reflect(reflect: &dyn #bevy_reflect_path::Reflect) -> #option<Self> {
if let #bevy_reflect_path::ReflectRef::#ref_struct_type(#ref_struct) = #bevy_reflect_path::Reflect::reflect_ref(reflect) {
#constructor
} else {
None
#option::None
}
}
}
Expand All @@ -153,7 +161,7 @@ fn get_ignored_fields(reflect_struct: &ReflectStruct, is_tuple: bool) -> MemberV

let value = match &field.attrs.default {
DefaultBehavior::Func(path) => quote! {#path()},
_ => quote! {Default::default()},
_ => quote! {::core::default::Default::default()},
};

(member, value)
Expand All @@ -172,6 +180,8 @@ fn get_active_fields(
struct_type: &Ident,
is_tuple: bool,
) -> MemberValuePair {
let option = quote!(::core::option::Option);

let bevy_reflect_path = reflect_struct.meta().bevy_reflect_path();

MemberValuePair::new(
Expand All @@ -189,19 +199,19 @@ fn get_active_fields(
let value = match &field.attrs.default {
DefaultBehavior::Func(path) => quote! {
(||
if let Some(field) = #get_field {
if let #option::Some(field) = #get_field {
<#ty as #bevy_reflect_path::FromReflect>::from_reflect(field)
} else {
Some(#path())
#option::Some(#path())
}
)
},
DefaultBehavior::Default => quote! {
(||
if let Some(field) = #get_field {
if let #option::Some(field) = #get_field {
<#ty as #bevy_reflect_path::FromReflect>::from_reflect(field)
} else {
Some(Default::default())
#option::Some(::core::default::Default::default())
}
)
},
Expand Down
Loading