diff --git a/src/solve/sharing-crates-with-rust-analyzer.md b/src/solve/sharing-crates-with-rust-analyzer.md index bf0d4fe3a1..8a96937b76 100644 --- a/src/solve/sharing-crates-with-rust-analyzer.md +++ b/src/solve/sharing-crates-with-rust-analyzer.md @@ -143,6 +143,119 @@ solver. This infrastructure is used by the external fuzzing project: . + +## `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`. + +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`, +Rust can then treat bounds such as the following as implied: + +```rust +I::Ty: Lift +I::Const: Lift +``` + +This allows `Lift_Generic` to emit the bound `I: LiftInto` 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` 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`. + +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` for a struct +or enum. It visits the value's fields in declaration order, delegating each +field to that field's own `TypeVisitable` 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`. 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` 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