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

Unable to use bevy_reflect derive macros when re-exported #1844

Closed
TehPers opened this issue Apr 7, 2021 · 5 comments
Closed

Unable to use bevy_reflect derive macros when re-exported #1844

TehPers opened this issue Apr 7, 2021 · 5 comments
Labels
A-Core Common functionality for all bevy apps A-Reflection Runtime information about types C-Bug An unexpected or incorrect behavior C-Code-Quality A section of code that is hard to understand or change

Comments

@TehPers
Copy link
Contributor

TehPers commented Apr 7, 2021

Bevy version

0.5.0

Operating system & version

Windows 10

What you did

  1. Create crate 'foo' with dependency bevy = "0.5.0"
  2. Re-export bevy
    pub use bevy;
  3. Create crate 'bar' with dependency on 'foo'
  4. Create a struct and derive 'TypeUuid':
    use foo::bevy::reflect::TypeUuid;
    
    #[derive(TypeUuid)]
    #[uuid = "e5bc46a0-56a6-41bb-8e56-cb9ab04d1efe"]
    struct Baz(i32);
  5. Code should fail to compile. Running cargo expand reveals that the macro is implementing crate::TypeUuid and using crate::Uuid, which should not exist (except TypeUuid if you're doing this in your crate root, but in any other module it shouldn't exist).

What you expected to happen

Derive macro should have attempted to implement bevy_reflect::TypeUuid, or there should have been a way to customize the crate path.

What actually happened

Running cargo expand reveals that the macro is implementing crate::TypeUuid, which does not exist.

#![feature(prelude_import)]
#[prelude_import]
use std::prelude::rust_2018::*;
#[macro_use]
extern crate std;
use foo::bevy::reflect::TypeUuid;
#[uuid = "e5bc46a0-56a6-41bb-8e56-cb9ab04d1efe"]
struct Baz(i32);
impl crate::TypeUuid for Baz {
    const TYPE_UUID: crate::Uuid = crate::Uuid::from_bytes([
        0xE5, 0xBC, 0x46, 0xA0, 0x56, 0xA6, 0x41, 0xBB, 0x8E, 0x56, 0xCB, 0x9A, 0xB0, 0x4D, 0x1E,
        0xFE,
    ]);
}

Additional information

By re-exporting TypeUuid and Uuid in the crate root, it's possible to make this still compile. While I can do that with my project, it seems like a workaround rather than a solution to the problem. I think that an attribute to specify where the bevy_reflect crate is at would help solve this issue.

@alice-i-cecile alice-i-cecile added C-Bug An unexpected or incorrect behavior A-Core Common functionality for all bevy apps C-Code-Quality A section of code that is hard to understand or change labels Apr 7, 2021
@YohDeadfall
Copy link
Member

@alice-i-cecile, since I recently played with macroses in Bevy, I would like to take it.

@alice-i-cecile
Copy link
Member

Sounds good @YohDeadfall!

@YohDeadfall
Copy link
Member

The $crate keyword exists only in scopes of macro_rules!and has a built in into the compiler logic. The compiler gets the nearest module first and expands it to a path, butproc-macro2 has no information about modules, it just provides a syntax tree to work on as an input.

While it's possible to create a macro rule to build a qualified path for the specified library and feed it unqualified names (qualified!(SomeType) producing $crate::SomeType), this macro should be located by a fully qualified name too in a procedural macros. Therefore, I don't think that there's a way to go without the compiler support.

An alternative approach is to traverse dependencies of the crate upward which will work in some cases, but it won't take modules into account and, therefore, will produce incorrect code which is harder to fix manually as @TehPers did.

@TehPers
Copy link
Contributor Author

TehPers commented Apr 10, 2021

I think that this could be solved using an attribute similar to serde's #[serde(crate = "...")] where you give the attribute (and thus the derive macro) the path to the bevy_reflect crate root. It might be worth noting that other bevy crates also have a #[as_crate] attribute (although I couldn't figure out the expected syntax for it).

The main issue I'm having with this crate vs. the other bevy crates is that this crate uses crate as the path to bevy_reflect when being re-exported whereas the other bevy crates use their respective crate names (bevy_ecs, bevy_render, etc). For example, to implement Bundle, I can do it like this:

// Import the bevy_ecs crate as bevy_ecs
use foo::bevy::{ ecs as bevy_ecs, prelude::* };

// implements bevy_ecs::bundle::Bundle
#[derive(Bundle)]
struct MyBundle {
    component: MyComponent,
}

If I were instead to derive TypeUuid, it would attempt to implement crate::TypeUuid rather than bevy_reflect::TypeUuid.

@YohDeadfall
Copy link
Member

Changing the path to bevy_reflect on failure seems reasonable since ecs does exactly that thing.

YohDeadfall added a commit to YohDeadfall/bevy that referenced this issue Apr 10, 2021
YohDeadfall added a commit to YohDeadfall/bevy that referenced this issue Apr 10, 2021
@alice-i-cecile alice-i-cecile added the A-Reflection Runtime information about types label Apr 14, 2021
YohDeadfall added a commit to YohDeadfall/bevy that referenced this issue Apr 26, 2021
YohDeadfall added a commit to YohDeadfall/bevy that referenced this issue May 7, 2021
@bors bors bot closed this as completed in 653c103 May 19, 2021
ostwilkens pushed a commit to ostwilkens/bevy that referenced this issue Jul 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Core Common functionality for all bevy apps A-Reflection Runtime information about types C-Bug An unexpected or incorrect behavior C-Code-Quality A section of code that is hard to understand or change
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants