Coinduction The trait solver may use coinduction when proving goals. Coinduction is fairly subtle so we're giving it its own chapter. Coinduction and induction With induction, we recursively apply proofs until we end up with a finite proof...
Caching in the new trait solver Caching results of the trait solver is necessary for performance. We have to make sure that it is sound. Caching is handled by the SearchGraph The global cache At its core, the cache is fairly straightforward...
Proof trees While the trait solver itself only returns whether a goal holds and the necessary constraints, we sometimes also want to know what happened while trying to prove it. While the trait solver should generally be treated as a black...
Opaque types in the new solver The way opaque types are handled in the new solver differs from the old implementation. This should be a self-contained explanation of the behavior in the new solver. Non-Defining vs Defining Uses The distinct...
Significant changes and quirks While some of the items below are already mentioned separately, this page tracks the main changes from the old trait system implementation. This also mentions some ways in which the solver significantly diverg...
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 low...
CoerceUnsized CoerceUnsized is primarily concerned with data containers. When a struct (typically, a smart pointer) implements CoerceUnsized, that means that the data it points to is being unsized. Some implementors of CoerceUnsized include...
Having separate Trait and Projection bounds Given T: Foo<AssocA = u32, AssocB = i32> where-bound, we currently lower it to a Trait(Foo<T>) and separate Projection(<T as Foo>::AssocA, u32) and Projection(<T as Foo>::AssocB, i32) bounds. Why...
Variance of type and lifetime parameters For a more general background on variance, see the background appendix. During type checking we must infer the variance of type and lifetime parameters. The algorithm is taken from Section 4 of the p...
Coherence NOTE: this is based on notes by @lcnr Coherence checking is what detects both of trait impls and inherent impls overlapping with others. (reminder: inherent impls are impls of concrete types like impl MyStruct {}) Overlapping trai...
HIR Type checking The hir_analysis crate contains the source for "type collection" as well as a bunch of related functionality. Checking the bodies of functions is implemented in the hir_typeck crate. These crates draw heavily on the type i...
Coercions Coercions are implicit operations which transform a value into a different type. A coercion site is a position where a coercion is able to be implicitly performed. There are two kinds of coercion sites: • one-to-one • LUB (Least-U...
Method lookup Method lookup can be rather complex due to the interaction of a number of factors, such as self types, autoderef, trait lookup, etc. This file provides an overview of the process. More detailed notes are in the code itself, na...
Const Generics Kinds of const arguments Most of the kinds of ty::Const that exist have direct parallels to kinds of types that exist, for example ConstKind::Param is equivalent to TyKind::Param. The main interesting points here are: • Const...
Opaque types (type alias impl Trait) Opaque types are syntax to declare an opaque type alias that only exposes a specific set of traits as their interface; the concrete type in the background is inferred from a certain set of use sites of t...
Inference of opaque types (impl Trait) This page describes how the compiler infers the hidden type for an opaque type. This kind of type inference is particularly complex because, unlike other kinds of type inference, it can work across fun...
Return Position Impl Trait In Trait Return-position impl trait in trait (RPITIT) is conceptually (and as of #112988, literally) sugar that turns RPITs in trait methods into generic associated types (GATs) without the user having to define t...
Opaque types region inference restrictions In this chapter we discuss the various restrictions we impose on the generic arguments of opaque types when defining their hidden types Opaque<'a, 'b, .., A, B, ..> := SomeHiddenType. These restric...
Effects, const traits, and const condition checking The HostEffect predicate HostEffectPredicates are a kind of predicate from [const] Tr or const Tr bounds. It has a trait reference, and a constness which could be Maybe or Const depending...
Pattern and exhaustiveness checking In Rust, pattern matching and bindings have a few very helpful properties. The compiler will check that bindings are irrefutable when made and that match arms are exhaustive. Pattern usefulness The centra...