Skip to content

Introduce ModernIdent type to unify macro 2.0 hygiene handling #144439

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

xizheyin
Copy link
Contributor

This pr introduce ModernIdent type to unify macro 2.0 hygiene handling

  1. Added ModernIdent type. Wraps Ident and automatically calls normalize_to_macros_2_0()
  2. Unified identifier normalization. Replaced scattered ident.normalize_to_macros_2_0() calls with ModernIdent::new(ident)

r? @petrochenkov

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Jul 25, 2025
@rustbot
Copy link
Collaborator

rustbot commented Jul 25, 2025

HIR ty lowering was modified

cc @fmease

@rustbot rustbot added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Jul 25, 2025
@fee1-dead
Copy link
Member

What problem is this intended to solve? ModernIdent seems like a quite confusing name.

/// different macro 2.0 macros.
// FIXME: Use more often
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
pub struct ModernIdent(pub Ident);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub struct ModernIdent(pub Ident);
pub struct Macros20NormalizedIdent(pub Ident);

The modern / legacy terminology for macros 2.0 / macro_rules is not used anymore.

}
}

impl std::borrow::Borrow<Ident> for ModernIdent {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any specific reason for this impl?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can convert it into Ident by passing a reference, and some parts of the code don't have to be changed to ident.0

Do I need to delete this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The by-ref coercions are enabled by Deref, if I understand the case correctly.
Also, Idents should usually be passed by value, unless some generic trait requires a reference.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agree with petrochenkov here. also I believe borrow generally should not be implemented for two types where one has more invariants than the other.

@@ -65,8 +65,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
fn compare_hygienically(&self, item1: ty::AssocItem, item2: ty::AssocItem) -> bool {
// Symbols and namespace match, compare hygienically.
item1.namespace() == item2.namespace()
&& item1.ident(self.tcx).normalize_to_macros_2_0()
== item2.ident(self.tcx).normalize_to_macros_2_0()
&& ModernIdent::new(item1.ident(self.tcx)) == ModernIdent::new(item2.ident(self.tcx))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think replacing the normalize_to_macros_2_0 calls in general is an improvement.
The new ident type makes sense only if it's stored in something or passed to something having an invariant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, so I need to delete some unnecessary substitutions.

impl ModernIdent {
#[inline]
pub fn new(ident: Ident) -> Self {
Self(ident.normalize_to_macros_2_0())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Self(ident.normalize_to_macros_2_0())
ModernIdent(ident.normalize_to_macros_2_0())

Could you avoid using Self outside of generic code?

}

#[inline]
pub fn with_dummy_span(name: Symbol) -> Self {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method isn't used anywhere.

@@ -1139,14 +1139,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}

pub(crate) fn check_reserved_macro_name(&self, ident: Ident, res: Res) {
pub(crate) fn check_reserved_macro_name(&self, ident: ModernIdent, res: Res) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
pub(crate) fn check_reserved_macro_name(&self, ident: ModernIdent, res: Res) {
pub(crate) fn check_reserved_macro_name(&self, ident: Ident, res: Res) {

This function would take a Symbol if it not needed the span for the error.
In general, for displaying spans non-normalized idents are better.

@petrochenkov petrochenkov added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jul 25, 2025
@petrochenkov
Copy link
Contributor

In general, I have mixed feelings about both this and MacroRulesNormalizedIdent.
It clearly can potentially catch some mistakes or inefficiencies (like it did in fn define_macro, I think), on the other hand it can only be used opportunistically because most places either do not care about the normalization, or care but the normalization should be different in different cases (like in rib.bindings, I guess).

Copy link
Contributor Author

@xizheyin xizheyin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this version, I removed some unnecessary uses.
The modifications are mainly centered around two fields.

  1. BindingKey::ident
  2. Resolver::extern_prelude

Comment on lines +2607 to +2610
// For search in index map for `Ident` as a index key
pub unsafe fn new_without_normalize(ident: Ident) -> Self {
Macros20NormalizedIdent(ident)
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the last commit, I implemented Borrow to look up in IndexMap<Macro20NormalizedIdent> with Ident as key. But in the new version, I implemented this function to temporarily convert the Ident to Macro20NormalizedIdent without normalizing it to match the type. And I also apply this function to some Idents that were not normalized using normalize_to_macros_2_0() in the original code.

I'll mark three places where I use this function and I'm not sure if I should use new or it.

@@ -203,7 +203,7 @@ impl<'a, 'ra, 'tcx> UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
if self
.r
.extern_prelude
.get(&extern_crate.ident)
.get(&unsafe { Macros20NormalizedIdent::new_without_normalize(extern_crate.ident) })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here use new_without_normalize for indexing

Comment on lines +325 to +328
let from_item = self
.extern_prelude
.get(&unsafe { Macros20NormalizedIdent::new_without_normalize(ident) })
.is_none_or(|entry| entry.introduced_by_item);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here also for Indexing

Comment on lines -1476 to +1496
.map(|(name, _)| (Ident::from_str(name), Default::default()))
.map(|(name, _)| {
(
unsafe {
Macros20NormalizedIdent::new_without_normalize(Ident::from_str(name))
},
Default::default(),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here will return extern_prelude which petrochenkov suggest to convert to Macro20NormalizedIdent.

Comment on lines 531 to +534
struct BindingKey {
/// The identifier for the binding, always the `normalize_to_macros_2_0` version of the
/// identifier.
ident: Ident,
ident: Macros20NormalizedIdent,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main Change(1/2)

Comment on lines -1043 to +1052
extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'ra>>,
extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'ra>>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main change (2/2)

@bors
Copy link
Collaborator

bors commented Jul 27, 2025

☔ The latest upstream changes (presumably #143884) made this pull request unmergeable. Please resolve the merge conflicts.

@bors
Copy link
Collaborator

bors commented Jul 30, 2025

☔ The latest upstream changes (presumably #144658) made this pull request unmergeable. Please resolve the merge conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants