rust-lang / lang-team

Home of the Rust lang team
http://lang-team.rust-lang.org/
Apache License 2.0
202 stars 48 forks source link

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

Open pnkfelix opened 1 year ago

pnkfelix commented 1 year ago

Summary

There's a future-incompat lint, proc_macro_derive_resolution_fallback (https://github.com/rust-lang/rust/issues/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" (https://github.com/rust-lang/rust/issues/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 commented 1 year ago

currently scheduled for 2023-02-15

pnkfelix commented 3 months ago

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?

pnkfelix commented 3 months ago

It is worth noting that there is potential overlap between the issues being explored here and the topics discussed in https://github.com/rust-lang/rfcs/pull/3373 and https://github.com/rust-lang/rust/issues/120363