Repository: rust
Issue: `$$crate` unexpectedly fails to defer which crate `$crate` refers to
Labels: P-medium,T-compiler,C-bug

<!--
Thank you for filing a bug report! 🐛 Please provide a short summary of the bug,
along with any information you feel relevant to replicating the bug.
-->

`$$` was stabilized in #95860 for 1.63. (reverted in #99435; now requires feature gate again.)

I tried this code:

```rust
// lib.rs
pub const WHICH: &str = "lib.rs";

#[macro_export]
macro_rules! define_which_macro {
    () => {
        macro_rules! which {
            () => {
                $$crate::WHICH
            };
        }
    };
}

// main.rs
use lib::define_which_macro;

pub const WHICH: &str = "main.rs";

define_which_macro!();

fn main() {
    dbg!(which!());
}
```

#### I expected to see this happen:

My intuitive expectation comes from expanding the macros as following:

```rust
define_which_macro!();
fn main() {
    dbg!(which!());
}
// =====>
macro_rules! which {
    () => {
        $crate::WHICH
    }
}
fn main() {
    dbg!(which!());
}
// =====>
fn main() {
    dbg!(crate::WHICH);
}
```

`lib` provides a macro whose expansion is specified to contain `$$ crate`; this seemingly should behave as writing `$crate` in the crate where the macro is expanded; i.e., `main.rs` should be printed.

#### Instead, this happened:

`lib.rs` is printed: the `$crate` in the expansion of `which!()` refers to `lib`.

This likely happens because the `$crate` compound identifier token refers to the crate indicated by the `crate` token's span, as indicated by the following example printing `main.rs`:

```rust
// lib.rs
#[macro_export]
macro_rules! define_which_macro {
    ($krate:tt) => {
        macro_rules! which {
            () => {
                $$$krate::WHICH
            };
        }
    };
}

// main.rs
define_which_macro!(crate);
fn main() {
    dbg!(which!());
}
```

and the following printing `lib.rs`:

```rust
// lib.rs
#[macro_export]
macro_rules! define_which_macro {
    ($d:tt) => {
        macro_rules! which {
            () => {
                $d crate::WHICH
            };
        }
    };
}

// main.rs
define_which_macro!($);
fn main() {
    dbg!(which!());
}
```

### Desired behavior

This seems *difficult* to resolve. The *stated purpose* of `$$` is to make writing macro-expanded-macros significantly more tractable than the previous `[$dollar:tt]` pattern defining a manual binder expanding to `$`. As such, it's fairly clearly the *intent* that writing `$$crate` should allow you to expand to a macro using `$crate` to refer to *its* defining crate, not the root macro's crate. (If you *want* the root macro's crate, you can already use just `$crate` just fine.)

Even though `$$` is unstable, though, refining this behavior might be edge-case breaking, as you could already observe the current behavior of `$crate`'s crate choice by using a manual `$dollar:tt` binder to get a `$` into the expanded output.

I have three concepts for how to make `$$crate` work as is likely intended:

#### `$crate` uses the `$` token's crate

... and `$$`'s expanded `$`'s crate gets set to the crate which expanded it, not the crate of either input `$`.[^1]

[^1]: I have no idea what span the expanded `$` gets currently. The "correct" choice is probably to take the span of the second input `$` as-is.

This changes the behavior of `$dollar $krate` to refer to `$dollar`'s crate rather than `$krate`'s crate.

#### `$crate` uses the "gluing" crate

When the `$crate` token is glued into a single ident token, it gets its crate set to the crate def which did the gluing.

This changes the behavior of the `$dollar $krate` to refer to the gluing crate rather than `$krate`'s crate.

##### Wait, which is the "gluing" crate then?

There's two options here:

- The crate for the `macro_rules!` name's token. This means that using a known name like in the original example would make `$$crate` behave the same as `$crate`, but would make most macro-defining-macros which take the name of the macro to define (or glue based on an input token using `paste!`, which respects the span of the first used binder) work as expected and produce a `$crate` referring to the crate which provided the name of the newly-defined macro. This also gives an easily predictable answer to what crate is referred to when multiple levels of macro indirection are involved.
- The crate the macro name is registered into the namespace of. It is the author's opinion that ***this is the most useful option***, as any other macro involved can insert a normal `$crate` token to refer to their namespace, and cannot refer to the crate any defined items end up in unless using a properly escaped `$$crate` refers to that crate.

#### Really kludge it just for `$$`

`$$` expands into a token that behaves like `$` *except for* the fact that `$crate` behaves like one of the previous two solutions when using a `$$`-created `$`.

This avoids changing the behavior of `$dollar $krate`, but makes `$dollar $krate` behave differently from `$$ $krate`.

### Meta
<!--
If you're using the stable version of the compiler, you should also check if the
bug also exists in the beta or nightly versions.
-->

`rustc --version --verbose`:
```
rustc 1.64.0-nightly (27eb6d701 2022-07-04)
binary: rustc
commit-hash: 27eb6d7018e397cf98d51c205e3576951d766323
commit-date: 2022-07-04
host: x86_64-pc-windows-msvc
release: 1.64.0-nightly
LLVM version: 14.0.6
```