I am creating an attribute macro that can be invoked with (a path to) some type amongst its attributes:
#[my_macro(path::to::SomeType)]
This macro generates a module, within which the specified type is to be used:
mod generated {
use path::to::SomeType;
}
However, from within that generated module, the path as provided may no longer be correct:
- if the path is prefixed with
::, it remains correct—I can determine this within the proc macro; - otherwise, if the path starts with an identifier that is in a prelude (such as that of an external crate), it remains correct—I can't see any way to determine this within the proc macro;
- otherwise it must now be prefixed with
super::for resolution to succeed.
Of course, I could require users of the macro to provide a path that will be correct from within the generated module, but that would not be very ergonomic.
Instead, I'm currently generating a type alias within the parent module:
type __generated_SomeType = path::to::SomeType;
mod generated {
use super::__generated_SomeType as SomeType;
}
However this is not only a tad clunky, but it furthermore pollutes the parent namespace.
Is there a better way?
I don't think there's a satisfying solution. But there's an alternative, and a way to improve your current approach.
The alternative is to use a
constitem:It can still cause name collisions with items from the parent scope, but at least the generated items aren't visible outside of the
const. This is what most macro authors do.If you don't want to do that, you can go with your current approach, but you should add
#[doc(hidden)]to the__generated_SomeTypetype, so it doesn't show up in documentation. Also, you should use an import instead of a type alias to support generic types, as suggested by @ChayimFriedman:I was just about to suggest combining these to approaches by putting a module inside a
constitem, but it doesn't work:Rust complains that
__generated_SomeTypedoesn't exist in the parent module.