-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[WIP] Expansion of #[derive(Trait)] macro attributes #1635
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
Conversation
|
||
use crate::{AstDatabase, HirFileId}; | ||
|
||
/// `AstId` points to an AST node in any file. | ||
/// | ||
/// It is stable across reparses, and can be used as salsa key/value. | ||
#[derive(Debug)] | ||
pub(crate) struct AstId<N: AstNode> { | ||
pub struct AstId<N: AstNode> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's better if this renmains `pub(crate)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Produces the following:
error[E0446]: crate-visible type `source_id::AstId<ra_syntax::ast::generated::MacroCall>` in public interface
--> crates/ra_hir/src/ids.rs:215:30
|
215 | Macro { def: MacroDefId, ast_id: AstId<ast::MacroCall> },
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-visible type
|
::: crates/ra_hir/src/source_id.rs:19:1
|
19 | pub(crate) struct AstId<N: AstNode> {
| ---------- `source_id::AstId<ra_syntax::ast::generated::MacroCall>` declared as crate-visible
@@ -132,6 +135,18 @@ impl AstIdMap { | |||
// trait does not change ids of top-level items, which helps caching. | |||
bfs(node, |it| { | |||
if let Some(module_item) = ast::ModuleItem::cast(it.clone()) { | |||
// Collect attributes from `StructDef`s and `EnumDef`s |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we store attributes as token trees in raw times, we wouldn't need to introduce ids for attributes, and this seems like a good thing to do
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what to do to resolve this.
|
||
fn implement_trait_simple(trait_name: &str, target: &ast::ModuleItem) -> Option<tt::Subtree> { | ||
if let Some(name) = item_name(target) { | ||
let impl_code = format!("impl {} for {} {{}}", trait_name, name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this won't work for generic types, but we can fix that later
"#, | ||
); | ||
|
||
assert_eq!("S", type_at_pos(&db, pos)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@flodiebold @matklad I've implemented an inference test, but it doesn't seem to work. The type inferred is {unknown}
. The problem is that #[derive(Clone)]
expands into impl Clone for S {}
token tree, but that doesn't seem to be correctly reflected further in HIR. If I replace derive with impl
block, everything works fine. Also, if I produce an impl block with macro_rules!
macro, the result is {unknown}
too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the problem is that macros are expanding into different file or module. Or some plumbing is still missing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, good to know... My guess would be that it's because impl blocks are collected separate from name resolution, though I don't know the macro infrastructure so well so I might be wrong. I'm not sure what the proper way to fix that would be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@matklad What do you think we should do here? Currently impl blocks are collected completely separately from nameres, but to keep that up we'd have to do macro expansion again there, I guess... Should DefCollector
just collect impl blocks as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I kinda stuck with this issue. Should try to collect impl
blocks too somehow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
impl block collection was imled in #1861
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, this test passes! 🎉
I have a feeling that this PR is getting out of hand, being sitting for more than a month and accumulating 25+ commits. However, I don't feel like the current state is what would be good to support long term. I see at least two problems:
Now, the best way to solve this would be for me to write "ten easy steps to implement attribute macro expansion in rust-analyzer", but unfortunately I don't have a precise design in mind. I also don't have time, right now, to produce such a design. I suggest putting the actual hacking on pause for a moment and try to co-design the end state of attribute expansion here: https://hackmd.io/@Ngg7W1yWSMySlEhnj8E5sw/HyyqCzIPB I am not sure that this is the right approach to designing things, but I definitely thing that repeatedly commenting on a PR which doesn't get the high-level structure right is not a good approach either. |
In this WIP PR, I'll try to build a ground to further resolve #1320 and #1427 by adding more thorough parsing and collecting of
#[derive(...)]
,#[must_use]
and other attributes and embedding them into code model or HIR so we can operate on them more easily. This would enable diagnostics and code generation for derives (as suggested by @matklad in #1427 (comment)).For now, I publishing this mostly to collect some feedback regarding design decisions and mentoring.
#[attr]
attributes as macros#[derive(Trait)] <item>
macros intoimpl Trait for <item> {}
#[derive(Trait)] <item>
for items with generic types#[derive]
should produce an error message (?)@matklad, @flodiebold