rust-lang/rust
HIR analysis and type checking
After lowering, rustc has a fully name-resolved HIR but still needs to assign types to expressions, check trait obligations, run lints, and verify well-formedness. Two crates do most of the heavy lifting.
rustc_hir_analysis — item-level checks
compiler/rustc_hir_analysis/ handles checks that operate at the item level:
- Collection — figuring out the type of every item (
type_of,fn_sig,predicates_ofqueries) from its HIR - Well-formedness — every type/clause is well-formed (e.g., bounds on generics are coherent, associated types are bounded)
- Coherence — no two
implblocks overlap (the orphan rule and friends). This is the core of trait soundness. - Variance — phantom variance computation for ADTs
- Outlives requirements — implicit
T: 'abounds derived from struct fields - Astconv — converting HIR types (which are syntactic) into
Ty<'tcx>(which are semantic)
These all run before per-function type checking and produce the queries that feed it.
rustc_hir_typeck — function-body type checking
compiler/rustc_hir_typeck/ is the per-function type checker. For every function body it:
- Sets up an
InferCtxtwith fresh inference variables for each unspecified type - Walks the HIR top-down, generating type and trait constraints
- Solves trait obligations against the constraint set
- Resolves inference variables to concrete types
- Reports type errors, suggesting fixes via diagnostics
It produces a TypeckResults<'tcx> keyed by HirId, recording the inferred type of every expression, the resolution of every method call, the type of every pattern binding, and the trait obligations satisfied along the way.
Pipeline
graph TB
HIR[(HIR after lowering)]
HIR --> Collect[Collection<br/>type_of, fn_sig,<br/>predicates_of, …]
Collect --> WF[Well-formedness checks]
WF --> Coherence[Coherence checks]
Coherence --> Typeck[rustc_hir_typeck<br/>per-fn typing]
Typeck --> Output[(TypeckResults<br/>per body)]
Output --> NextStage[MIR build]The collection / well-formedness / coherence steps are queries — they're computed lazily when other parts of the compiler ask. rustc_hir_typeck::typecheck_item_bodies is the entry point that demands them all at once.
Inference walkthrough
Take fn add(a: i32, b: i32) -> i32 { a + b }. Type checking proceeds:
- Function signature —
fn_sigquery returnsfn(i32, i32) -> i32.aandbare bound asi32. - Body type — fresh inference variable
?Tintroduced for the body. - Expression
a + b— looks up<i32 as Add<i32>>::add. TheAddtrait is satisfied. Result type isi32. - Tail constraint —
?T = i32(because the body's last expression must equal the return type). - Resolution —
?Tresolves toi32. No errors.
For complex examples involving closures, async, and trait inference, the work is much heavier — but the structure is the same.
Method resolution
Method calls (x.foo()) are resolved by rustc_hir_typeck::method, which:
- Builds a list of candidate methods (inherent
impls, then traitimpls in scope) considering autoderef and autoref - Picks the most specific candidate
- Generates the obligations needed to satisfy the chosen
impl's where-clauses
Method resolution is a frequent source of subtle bugs because it interacts with autoderef, autoref, dyn dispatch, and inference simultaneously.
Coercions
Implicit conversions (&T → &dyn Trait, &[T; N] → &[T], Box<T> → Box<dyn Trait>) are handled by rustc_hir_typeck::coercion. Coercions are numbered and sequenced; complex coercion paths can produce CoerceMany records.
Diagnostics
Type errors are some of rustc's most user-visible output. The frontend goes to extra effort to produce them well:
- Suggestion machinery —
tcx.dcx().struct_span_err(...).help_with_suggestion(...)produces actionable hints - Trait engine fallbacks — when a trait obligation fails, the trait engine produces a list of why
note: expected … found …— formatting unifies the printer with the type-error formatter
Patterns to look for in diagnostics code: try_report_*, suggest_*, note_* methods on the relevant context.
Lints in the analysis phase
Some lints run during HIR analysis (for items, attributes, dead code, unused imports). Others run later, on MIR (unused_assignments, dead-store removal). The framework is in rustc_lint and lint definitions in rustc_lint_defs.
Pattern exhaustiveness
Pattern matching exhaustiveness (match x { … } covers every case) is checked separately by rustc_pattern_analysis. The crate is shared with rust-analyzer (it's published to crates.io as well). The algorithm is based on Maranget's "Compiling Pattern Matching to Good Decision Trees" and is one of the cleaner stand-alone pieces of the type-checker.
Privacy
rustc_privacy checks visibility on item references after type checking. It enforces:
- You can only reference items you can name (
pub(crate),pub(super), …) - You can't expose more in your public API than you have visibility for ("private-in-public" lint)
Key files
| File | What |
|---|---|
compiler/rustc_hir_analysis/src/lib.rs |
Top-level entry, registers queries |
compiler/rustc_hir_analysis/src/collect.rs |
"Collect" pass — types/preds/sigs from HIR |
compiler/rustc_hir_analysis/src/coherence/ |
Coherence/orphan checks |
compiler/rustc_hir_typeck/src/lib.rs |
Per-function entry |
compiler/rustc_hir_typeck/src/fn_ctxt/ |
The FnCtxt that holds typeck state |
compiler/rustc_hir_typeck/src/method/ |
Method resolution |
compiler/rustc_hir_typeck/src/expr_use_visitor.rs |
Closure capture analysis |
Entry points for modification
- A new diagnostic suggestion in typeck → find the relevant
report_*orsuggest_*method - New rule for method dispatch →
rustc_hir_typeck::method - Item-level well-formedness change →
rustc_hir_analysis::check::wfcheck - New lint that wants HIR access → register a
LateLintPassinrustc_lint::late - Pattern-exhaustiveness rule →
rustc_pattern_analysis
See also
- Type system — the data structures consumed here
- MIR — what runs after type checking
- Diagnostics — how to wire user-facing errors
- rustc-dev-guide: HIR
- rustc-dev-guide: type checking
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.