-
-
Notifications
You must be signed in to change notification settings - Fork 313
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
Finding out if type implements a particular trait #77
Comments
No it's not possible in a procedural macro. During macro expansion the only thing that exists is the syntax tree of your program (basically the text of your program) and that is the only thing macros, whether procedural or macro_rules, are operating on. The compiler has not put together type information about anything yet, doesn't know what type a particular name refers to, doesn't know what crate that type might come from, doesn't even know whether something with that name exists. All of that is figured out after macro expansion is done. Can you explain a bit more about your use case? There might be an alternative way to accomplish the same thing. |
I'm working on a new crate to derive errors using Macros 1.1. As you already know, error types must implement Instead of requiring users to submit only objects that implement The reason I want to do it this way is that I have noticed that quite a few libraries do not implement |
I think we can make this work using specialization, although that feature is still unstable. The idea would be something like this: trait AsError {
fn as_error(&self) -> Option<&Error>;
}
impl<T> AsError for T {
default fn as_error(&self) -> Option<&Error> { None }
}
impl<T> AsError for T where T: Error {
fn as_error(&self) -> Option<&Error> { Some(self) }
} Then if you have a variable |
Thanks for the tip. I will probably create a nightly feature that uses I typically code against stable because I plan to use the libraries I'm working on in production very soon. The only reason I'm using procedural macros now is that they will be in |
trait AsError {
fn as_error(&self) -> Option<&Error>;
}
impl AsError for Error {
fn as_error(&self) -> Option<&Error> { Some(self) }
}
impl<T> AsError for T {
fn as_error(&self) -> Option<&Error> { None }
} That compiles fine on stable but when I try it within
I tried increasing recursion limit to 1024 ( |
If I move that out into the crate that's calling |
Yeah that code is different from the code using specialization. I think you need specialization to make this work ergonomically, can't think of a way to do it on stable. You would need the user to indicate to you in some way whether or not the thing implements std::error::Error, possibly using an attribute like these. Then you can generate different code for the two cases. In my version I have an impl returning None that applies to all Sized types T, and I have an impl returning Some that applies to all Sized types T where T implements Error. Note that there are some types for which both of these impls apply, so we need specialization in order for the compiler to tell which one "applies more" in some sense. In your version you have an impl returning None that applies to all Sized types T, and an impl returning Some that applies to the dynamically sized (unsized) type Error which is the trait object associated with the Error trait. There are no types for which both of these impls apply, which is why it works without specialization and on stable. You can actually get it to return Some if you have a trait object: https://is.gd/qRK7JH but this is not what you want. |
Thanks again. I think attributes would be good enough for now. How does one define their own attributes on stable? I can't seem to find any documentation for it. |
Here is an example from the heapsize_derive crate: https://github.com/servo/heapsize/blob/v0.3.8/derive/lib.rs#L13 #[proc_macro_derive(HeapSizeOf, attributes(ignore_heap_size_of))] This defines the The attributes will be part of the syntax tree you get when you parse the input to your macro. They can show up in a few different places depending on where in the input the user wrote them. #[my_attr] // syn::MacroInput::attrs
enum E {
#[my_attr] // syn::Variant::attrs
V {
#[my_attr] // syn::Field::attrs
f: u8
}
} Here is where the heapsize_derive crate loops over field attributes: https://github.com/servo/heapsize/blob/v0.3.8/derive/lib.rs#L23-L33 For now attributes can be pretty tedious to work with but in #25 we have been thinking of ways to make this better. |
Awesome. I can't thank you enough for all the help you have given me and your patience. As for defining attributes, I can't believe it's that simple. Which reminds me... Where can I find the documentation for the |
I don't think it is available officially yet. Manish is hosting it here for now: https://manishearth.github.io/rust-internals-docs/proc_macro/ |
Sweet! Thanks a lot! |
Say I have a type
Foo
. Is it possible to find out if it implements a certain traitBar
? In my particular case I want to find out if a certain type implementsstd::error::Error
in a macros 1.1 macro./cc @dtolnay
The text was updated successfully, but these errors were encountered: