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

Tracking issue for procedural macros and "hygiene 2.0" #54727

Open
alexcrichton opened this Issue Oct 1, 2018 · 18 comments

Comments

Projects
None yet
7 participants
@alexcrichton
Copy link
Member

alexcrichton commented Oct 1, 2018

This is intended to be a tracking issue for enabling procedural macros to have "more hygiene" than the copy/paste hygiene they have today. This is a very vague tracking issue and there's a very long and storied history to this. The intention here though is to create a fresh tracking issue to collect the current state of play, in hopes that we can close some of the much older and very long issues which contain lots of outdated information.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 1, 2018

To give some background, feature(proc_macro_hygiene) tracked by this issue was merged from multiple features (proc_macro_mod, proc_macro_expr, proc_macro_non_items, proc_macro_gen) in #52121.

So, it's pretty heterogeneous and is not even entirely about hygiene.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 1, 2018

Copypasting what I wrote in #52121:

None of these features is blocked on hygiene, except for proc_macro_gen.

  • proc_macro_mod is, IIRC, about expanding inner attributes and expanding non-inline modules (mod foo;). I'm not sure why #[my_macro] mod m { ... } with outer attribute and inline module is still gated, I'm not aware of any reasons to not stabilize it.
  • proc_macro_expr/proc_macro_non_items have no reasons to be gated as well and can be stabilized after some implementation audit. Proc macros have well-defined "copy-paste" Span::call_site() hygiene, this includes "unhygienic" use of local variables.
    IIRC, @nrc assumed that additional feature gates would prevent interactions of that copy-paste hygiene with local variables, but that's not true - you can easily expand an item and inject tokens from the outside into its body (e.g. #50050), causing exactly the same interactions.

What is really blocked on hygiene is Span::def_site() and decl_macro (which is also blocked on a ton of other stuff).

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 1, 2018

proc_macro_gen is more about interactions between Span::call_site hygiene (entirely unhygienic) and macro_rules hygiene (unhygienic except for local variables and labels).

alexcrichton added a commit to alexcrichton/rust that referenced this issue Oct 1, 2018

@CodeSandwich

This comment has been minimized.

Copy link

CodeSandwich commented Oct 1, 2018

This looks like the right branch for this question. Sorry about copy-paste, but I really need to know.

It seems that since rustc 1.30.0-nightly (63d51e89a 2018-09-28) it is no longer possible to traverse code inside module in separate file. If you process mod module;, you get TokenStream containing mod module;, WYSIWYG.

I understand, that this is necessary in order to preserver spans, hygiene and consistency with processed code. Is there or will be any way to work with content of modules in separate files? Its lack may be confusing for end users when trivial refactoring of module organization causes change in macro behavior.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 2, 2018

@CodeSandwich
This may be a regression from #52319 perhaps?

cc @tinco

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 2, 2018

I understand, that this is necessary in order to preserver spans, hygiene and consistency with processed code.

From what I remember, this is an open question.
The transformation mod m; -> mod m { ... } is an expansion of sorts, and we may treat it both as an early expansion (like e.g. #[cfg], which is also expanded before passing the item to attribute-like macros) and as a late expansion (the item is not expanded before being passed to macros).

The "early expansion behavior" looks preferable to me, and this change in behavior looks like a bug rather than a fix.

@tinco

This comment has been minimized.

Copy link
Contributor

tinco commented Oct 2, 2018

I lack some context, so I can't be certain, what exactly is "process"? If it relies on rustc's pretty printing, then yes this would be a consequence of #52319, and it should be simple to fix by changing the invocation I think. #52319 does two things:

  1. Add information to the AST (a single bool, tracking if a mod is inline)
  2. Make pretty print no longer print the external file if that bool is false

If you need the expanded file, then that should be made explicit in the invocation of the pretty printer.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 2, 2018

Yes, the change is likely due to the pretty-printing change.
So it can be fixed either by reverting the change, or making it more fine-grained so it prints the contents regardless of the inline flag if pretty-printing is done "for proc macros" (whatever that means).

@tinco

This comment has been minimized.

Copy link
Contributor

tinco commented Oct 2, 2018

If you can point me at the line of code that invokes the pretty printer, I can suggest a fix.

@CodeSandwich

This comment has been minimized.

Copy link

CodeSandwich commented Oct 2, 2018

By "processing" I mean parsing TokenStream with Syn to an Item, modifying its content and converting it back to TokenStream. The precise spot of parsing is here and content traversal is there. I haven't dug into implementation of Syn yet, so I can't tell for sure if it uses pretty printing. I've set nightly feature in Syn, which as far as I know skips step of printing and parsing the string again.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Oct 2, 2018

I personally feel that what a proc macro receives as input tokens when attached to a module is an open questions, as @petrochenkov said. I do not think that one answer is clearly correct over another (mod foo; vs mod foo { ... }) at this time. That's why it's unstable!

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Oct 18, 2018

I'm confused why proc macros expanding to macro_rules! definitions is gated.
(especially when the new macros are only invoked by other expanded items)

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 18, 2018

@eddyb
Well, the answer is "not enough confidence in correctness of hygiene interactions between transparent (procedural on stable) and semi-transparent (macro_rules) macros".

I hoped to at least get rid of the "context transplantation trick" before stabilizing it, but got distracted by the edition stuff.

It generally works though, I'm not aware of any specific bugs manifesting in normal cases.

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Oct 18, 2018

$crate in generated macros concerns me in particular.
(I don't remember whether it works correctly now, need to test.)

@dbeckwith

This comment has been minimized.

Copy link

dbeckwith commented Jan 3, 2019

rustc pointed me to this issue because I tried to use a proc macro in a type context (procedural macros cannot be expanded to types), but I don't see anything about this usage in the discussion. Is this the right issue to track that feature?

@jebrosen

This comment has been minimized.

Copy link
Contributor

jebrosen commented Jan 4, 2019

@dbeckwith proc_macro_non_items was originally introduced in #50120, and I renamed it to be part of proc_macro_hygiene in #52121. I reviewed several of the discussions on both PRs and discussions that led to them and can't find any actual discussion of expanding types in particular. There has been some disagreement on exactly what should still be gated or not and why, but mostly with respect to statements and expressions.

@alexcrichton -- do you remember a reason for gating expansion to types, other than "types are not items"?
@nrc -- do your concerns from #52121 (comment) also apply to types, or only to expressions, statements, and presumably patterns?

@petrochenkov

This comment has been minimized.

Copy link
Contributor

petrochenkov commented Jan 4, 2019

I'm not aware of any issues preventing stabilization of fn-like macros expanding into types.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Jan 4, 2019

@jebrosen IIRC it's just "types weren't items" at the time, so if others agree seems like we could stabilize it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment