From fd3d8577b7e0ec17ead6b86a1b5795a9104ea79b Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Tue, 2 Dec 2025 17:06:10 +0900 Subject: [PATCH] Mention sharing the solver with rust-analyzer --- src/SUMMARY.md | 1 + .../sharing-crates-with-rust-analyzer.md | 109 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src/solve/sharing-crates-with-rust-analyzer.md diff --git a/src/SUMMARY.md b/src/SUMMARY.md index c136d3716..1490db880 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -185,6 +185,7 @@ - [Proof trees](./solve/proof-trees.md) - [Opaque types](./solve/opaque-types.md) - [Significant changes and quirks](./solve/significant-changes.md) + - [Sharing the trait solver with rust-analyzer](./solve/sharing-crates-with-rust-analyzer.md) - [`Unsize` and `CoerceUnsized` traits](./traits/unsize.md) - [Variance](./variance.md) - [Coherence checking](./coherence.md) diff --git a/src/solve/sharing-crates-with-rust-analyzer.md b/src/solve/sharing-crates-with-rust-analyzer.md new file mode 100644 index 000000000..460f85ce6 --- /dev/null +++ b/src/solve/sharing-crates-with-rust-analyzer.md @@ -0,0 +1,109 @@ +# Sharing the trait solver with rust-analyzer + +rust-analyzer can be viewed as a compiler frontend: it performs tasks similar to the parts of rustc +that run before code generation, such as parsing, lexing, AST construction and lowering, HIR +lowering, and even limited MIR building and const evaluation. + +However, because rust-analyzer is primarily a language server, its architecture differs in several +important ways from that of rustc. +Despite these differences, a substantial portion of its responsibilities—most notably type +inference and trait solving—overlap with the compiler. + +To avoid duplication and to maintain consistency between the two implementations, rust-analyzer +reuses several crates from rustc, relying on shared abstractions wherever possible. + +## Shared Crates + +Currently, rust-analyzer depends on several `rustc_*` crates from the compiler: + +- `rustc_abi` +- `rustc_ast_ir` +- `rustc_index` +- `rustc_lexer` +- `rustc_next_trait_solver` +- `rustc_parse_format` +- `rustc_pattern_analysis` +- `rustc_type_ir` + +Since these crates are not published on `crates.io` as part of the compiler's normal distribution +process, rust-analyzer maintains its own publishing pipeline. +It uses the [rustc-auto-publish script][rustc-auto-publish] to publish these crates to `crates.io` +with the prefix `ra-ap-rustc_*` +(for example: https://crates.io/crates/ra-ap-rustc_next_trait_solver). +rust-analyzer then depends on these re-published crates in its own build. + +For trait solving specifically, the primary shared crates are `rustc_type_ir` and +`rustc_next_trait_solver`, which provide the core IR and solver logic used by both compiler +frontends. + +## The Abstract Layer + +Because rust-analyzer is a language server, it must handle frequently changing source code and +partially invalid or incomplete source codes. +This requires an infrastructure quite different from rustc's, especially in the layers between +the source code and the HIR—for example, `Ty` and its backing interner. + +To bridge these differences, the compiler provides `rustc_type_ir` as an abstract layer shared +between rustc and rust-analyzer. +This crate defines the fundamental interfaces used to represent types, predicates, and the context +required by the trait solver. +Both rustc and rust-analyzer implement these traits for their own concrete type representations, +and `rustc_next_trait_solver` is written to be generic over these abstractions. + +In addition to these interfaces, `rustc_type_ir` also includes several non-trivial components built +on top of the abstraction layer—such as elaboration logic and the search graph machinery used by the +solver. + +## Design Concepts + +`rustc_next_trait_solver` is intended to depend only on the abstract interfaces defined in +`rustc_type_ir`. +To support this, the type-system traits in `rustc_type_ir` must expose every interface the solver +requires—for example, [creating a new inference type variable][ir new_infer] +([rustc][rustc new_infer], [rust-analyzer][r-a new_infer]) +For items that do not need compiler-specific representations, `rustc_type_ir` defines them directly +as structs or enums parameterized over these traits—for example, [`TraitRef`][ir tr]. + +The central trait in this design is [`Interner`][ir interner], which specifies all +implementation-specific details for both rustc and rust-analyzer. +Among its essential responsibilities: + +- it **specifies** the concrete types used by the implementation via its + [associated types][ir interner assocs]; these form the backbone of how each compiler frontend + instantiates the shared IR, +- it provides the context required by the solver (e.g., querying [lang items][ir require_lang_item], + enumerating [all blanket impls for a trait][ir for_each_blanket_impl]); +- and it must implement [`IrPrint`][ir irprint] for formatting and tracing. + In practice, these `IrPrint` impls simply route to existing formatting logic inside rustc or + rust-analyzer. + +In general, we aim to support rust-analyzer just as well as rustc in these shared crates—provided +doing so does not substantially harm rustc's performance or maintainability. +(e.g., [#145377][pr 145377], [#146111][pr 146111], [#146182][pr 146182] and [#147723][pr 147723]) + +Shared crates that require nightly-only features must guard such code behind a `nightly` feature +flag, since rust-analyzer is built with the stable toolchain. + +Looking forward, we plan to uplift more shared logic into `rustc_type_ir`. +There are still duplicated implementations between rustc and rust-analyzer—such as `ObligationCtxt` +([rustc][rustc oblctxt], [rust-analyzer][r-a oblctxt]) and type coercion logic +([rustc][rustc coerce], [rust-analyzer][r-a coerce])—that we would like to unify over time. + +[rustc-auto-publish]: https://github.com/rust-analyzer/rustc-auto-publish +[ir new_infer]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/inherent/trait.Ty.html#tymethod.new_infer +[rustc new_infer]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_middle/src/ty/sty.rs#L413-L420 +[r-a new_infer]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/next_solver/ty.rs#L59-L92 +[ir tr]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/struct.TraitRef.html +[ir interner]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html +[ir interner assocs]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#required-associated-types +[ir require_lang_item]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#tymethod.require_lang_item +[ir for_each_blanket_impl]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/trait.Interner.html#tymethod.for_each_blanket_impl +[ir irprint]: https://doc.rust-lang.org/1.91.1/nightly-rustc/rustc_type_ir/ir_print/trait.IrPrint.html +[pr 145377]: https://github.com/rust-lang/rust/pull/145377 +[pr 146111]: https://github.com/rust-lang/rust/pull/146111 +[pr 146182]: https://github.com/rust-lang/rust/pull/146182 +[pr 147723]: https://github.com/rust-lang/rust/pull/147723 +[rustc oblctxt]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_trait_selection/src/traits/engine.rs#L48-L386 +[r-a oblctxt]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/next_solver/obligation_ctxt.rs +[rustc coerce]: https://github.com/rust-lang/rust/blob/63b1db05801271e400954e41b8600a3cf1482363/compiler/rustc_hir_typeck/src/coercion.rs +[r-a coerce]: https://github.com/rust-lang/rust-analyzer/blob/34f47d9298c478c12c6c4c0348771d1b05706e09/crates/hir-ty/src/infer/coerce.rs \ No newline at end of file