Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 113 additions & 0 deletions src/solve/sharing-crates-with-rust-analyzer.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,119 @@ solver.
This infrastructure is used by the external fuzzing project:
<https://github.com/lcnr/search_graph_fuzz>.


## `rustc_type_ir` Macros

`rustc_type_ir` makes _heavy_ use of a few macros, in particular
- [`Lift_Generic`][lift_generic]
- [`TypeFoldable_Generic`][typefoldable_generic]
- [`TypeVisitable_Generic`][typevisitable_generic]
- [`GenericTypeVisitable`][generictypevisitable]

Of which primarily exist to reduce the amount of boilerplate otherwise
required to implement `TypeFoldable`, `TypeVisitable` and `Lift`.
Comment on lines +149 to +156

@lcnr lcnr Jul 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
`rustc_type_ir` makes _heavy_ use of a few macros, in particular
- [`Lift_Generic`][lift_generic]
- [`TypeFoldable_Generic`][typefoldable_generic]
- [`TypeVisitable_Generic`][typevisitable_generic]
- [`GenericTypeVisitable`][generictypevisitable]
Of which primarily exist to reduce the amount of boilerplate otherwise
required to implement `TypeFoldable`, `TypeVisitable` and `Lift`.
`rustc_type_ir` makes _heavy_ use of a few macros, in particular
- [`Lift_Generic`][lift_generic]
- [`TypeFoldable_Generic`][typefoldable_generic]
- [`TypeVisitable_Generic`][typevisitable_generic]
- [`GenericTypeVisitable`][generictypevisitable]
Of which primarily exist to reduce the amount of boilerplate otherwise
required to implement `TypeFoldable`, `TypeVisitable` and `Lift`.
These macros are variants of the `TypeFoldable`, `TypeVisitable`, and `Lift` macros used in crates which have access to the `TyCtxt` using a `I: Interner` parameter instead of `TyCtxt`.

View changes since the review


These macros are variants of the `TypeFoldable`, `TypeVisitable`, and `Lift`
macros used in crates which have access to the `TyCtxt` using a `I: Interner`
parameter instead of `TyCtxt`.

### `Lift_Generic`
[lift_generic]: #lift_generic

Derives `Lift` for a struct or enum, with three curious properties:

**quirk 1:**
The generic parameters `I` and `J` are reserved for `I: Interner` and `J`
being the interner it is being lifted to.

**quirk 2:**
`PhantomData` is handled automatically, creating a new `PhantomData` but
_has_ to be included in the file through; `use std::marker::PhantomData;`
you cannot use `std::marker::PhantomData` directly on the field of a struct.

**quirk 3:**
The bounds are deliberately written as associated type bounds on the `Interner`
trait rather than as `where` clauses on `LiftInto`. Given only `I: LiftInto<J>`,
Rust can then treat bounds such as the following as implied:

```rust
I::Ty: Lift<J, Lifted = J::Ty>
I::Const: Lift<J, Lifted = J::Const>
```

This allows `Lift_Generic` to emit the bound `I: LiftInto<J>` while still
calling `lift_to_interner` on fields of type `I::Ty`, `I::Const`, and the other
declared associated types. It also guarantees that each call produces the
destination field type expected after the derive rewrites `I::Assoc` to
`J::Assoc`.

Without `declare_lift_into!`, the derive would need to generate a separate bound
for every interner-associated type used by every field. If a new `Interner`
associated type is expected to work with `Lift_Generic`, it needs an appropriate
`Lift` implementation and normally needs to be included in the
`declare_lift_into!` invocation.

If you want to ignore a file, such as a primitive like a `u32` which can't be
lifted you can skip the field with `#[lift(ignore)]`.

### `TypeFoldable_Generic`
[typefoldable_generic]: #typefoldable_generic

`TypeFoldable_Generic` derives `rustc_type_ir::TypeFoldable<I>` for a struct or
enum.

It consumes a value and reconstructs the same struct or enum variant after
folding its fields. It generates both fallible and infallible folding methods.

Use `#[type_foldable(identity)]` for a field whose value must be preserved
unchanged. The macro moves that field directly into the reconstructed value
instead of passing it to the folder. Its type therefore does not need to
implement `TypeFoldable<I>`.

For an enum, the generated match contains one reconstruction arm per variant.

### `TypeVisitable_Generic`
[typevisitable_generic]: #typevisitable_generic

`TypeVisitable_Generic` derives `rustc_type_ir::TypeVisitable<I>` for a struct
or enum. It visits the value's fields in declaration order, delegating each
field to that field's own `TypeVisitable<I>` implementation. The traversal can
stop early if the visitor returns a residual result.

Use `#[type_visitable(ignore)]` to ignore a field; it will not be part of the
traversal and will not need to implement `TypeVisitable<I>`. This should only
be used when the field does not need to be traversed.

### `GenericTypeVisitable`
[generictypevisitable]: #generictypevisitable

While ostensibly similar due to their names, they implement two different
visiting systems.

- `TypeVisitable_Generic` means: derive the ordinary `TypeVisitable` trait
generically over an `Interner`.
- `GenericTypeVisitable` means: derive the separate `GenericTypeVisitable` trait
used by non-nightly consumers such as rust-analyzer.

As such a struct or enum can derive both `TypeVisitable_Generic` and
`GenericTypeVisitable`

`GenericTypeVisitable` derives `rustc_type_ir::GenericTypeVisitable<V>` for a
struct or enum.

This a separate more general traversal trait purely used by rust-analyzer.
The visitor type is a parameter of the trait rather than a parameter of the
method, and visiting neither returns a result nor supports short-circuiting.

There is intentionally no ignore attribute. The traversal must visit every
field. This is a soundness requirement for rust-analyzer's use of the traversal
when tracing and garbage-collecting interned types.

When the macro crate's `nightly` feature is enabled, the derive macro remains
registered but emits no tokens. The `GenericTypeVisitable` trait and its
traversal module are also excluded from the nightly configuration of
`rustc_type_ir`; they exist only in its non-nightly configuration.

## Long-term plans for supporting rust-analyzer

In general, we aim to support rust-analyzer just as well as rustc in these shared crates—provided
Expand Down
Loading