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

discuss/resolve fn { mod { (use) super::...; } } and its interaction with derive patterns #193

Open
pnkfelix opened this issue Jan 31, 2023 · 3 comments
Labels
meeting-proposal Proposal for a lang team design meeting T-lang

Comments

@pnkfelix
Copy link
Member

Summary

There's a future-incompat lint, proc_macro_derive_resolution_fallback (rust-lang/rust#83583), which seemed like a slam dunk, but moving it to a hard error had unexpected repercussions due to a slight expressiveness limitation, "Paths involving 'super' don't work from within a function" (rust-lang/rust#64079).

I want to meet to survey the solutions (I believe two have been proposed and I want to put forward at least a third) and evaluate whether to push aggressively to re-hard-error proc_macro_derive_resolution_fallback or if we want to make some language change first to better serve authors of derive macros.

Background reading

pnkfelix will prepare a doc.

but in the meantime, there are the links in the description given above.

About this issue

This issue corresponds to a lang-team design meeting proposal. It corresponds to a possible topic of discussion that may be scheduled for deeper discussion during one of our design meetings.

@pnkfelix
Copy link
Member Author

currently scheduled for 2023-02-15

@pnkfelix pnkfelix added the meeting-scheduled Lang team design meeting that has a scheduled date label Feb 10, 2023
@tmandry tmandry removed the meeting-scheduled Lang team design meeting that has a scheduled date label Apr 5, 2023
@pnkfelix
Copy link
Member Author

pnkfelix commented Jul 31, 2024

everytime I look at this I have to reload a bunch of context.

Here is an attempt at an executive summary:

  1. People want to be able to write derive macros that expand to code. They want that code to be able to be contained within its own modules.
    • This means that you want to be able to write #[derive(ExpandsToMod)] struct Foo; and have that expand into something like struct Foo; mod expanded { impl other_crate::Trait for super::Foo { } }
  2. People also commonly write items inside of function bodies. E.g. fn bar() { struct Baz; }.
    • (Notably, rustdoc uses that pattern to create the Rust code that drives test snippets; so even if you don't write code like that often yourself, it does arise in very common expanded code today.)
  3. Combining 1 and 2 above, you end up with people trying to write fn bar() { #[derive(ExpandsToMod)] struct Baz; }
  4. But then you hit the issue at hand here: If you follow the same expansion there, you end up with fn bar() { struct Baz; mod expanded { impl other_crate::Trait for super::Baz { } }.
    • And that does not compile; the super::Baz within the expanded mod only has access to items in the module parent of fn bar, not within the body of fn bar itself.

So then you hit upon the question: What is the right thing to do about this?

  • An answer, "extend path expressiveness": expand the path syntax to allow code to refer to fn-scopes rather than just module scopes.
  • An answer "extend mod expressiveness": extend our module system to allow people to write "transparent" modules that immediately inherit all names that are available in their parent scope
  • An answer "defensive macrology": write your derive macros to not contain their code in modules, but instead in e.g. const _: () = { /* contents */ }: Paths involving 'super' don't work from within a function rust#64079 (comment)
    • I believe this to be current "best practice" for derive macro authors.
  • An answer "change fn scope semantics": instead of trying to extend the language (in potentially awkward ways) is to make a potentially breaking change over an edition of the language.
    • E.g. change fn bodies such that they transparently extend the "current scope" (for the extent of that fn body) such that sub-modules within the fn now have access to all items added by that fn body (and those added items shadow any items from the parent of the fn).
    • Here is why the aforementioned idea is a breaking change that would need to be added over an edition: playpen.

@pnkfelix
Copy link
Member Author

It is worth noting that there is potential overlap between the issues being explored here and the topics discussed in rust-lang/rfcs#3373 and rust-lang/rust#120363

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
meeting-proposal Proposal for a lang team design meeting T-lang
Projects
Status: Needs triage
Development

No branches or pull requests

2 participants