This page covers rustc_resolve, the crate responsible for the part of name resolution that does not require type information. It assigns a resolved definition (Res) to every identifier, path, label, lifetime, and macro invocation in a Rust crate. Because macros can introduce new items and imports, and imports can resolve to macros, macro expansion and name resolution are tightly interleaved—they do not run as separate sequential phases.
For the parsing phase that produces the initial AST consumed here, see Parsing and AST Construction. For type-relative resolution (method lookup, associated items, field access), see Type Checking and Method Resolution. For how resolved names are converted to HIR node IDs, see AST to HIR Lowering.
All code covered here lives in compiler/rustc_resolve/.
| Source module | Primary responsibility |
|---|---|
src/lib.rs | Resolver struct; core types: Module, Decl, Scope, ParentScope, NameResolution |
src/build_reduced_graph.rs | Integrates expanded AST fragments into the module tree |
src/imports.rs | Import resolution: ImportData, NameResolution, iterative resolution loop |
src/macros.rs | ResolverExpand implementation, MacroRulesScope, macro path resolution |
src/def_collector.rs | DefCollector: assigns LocalDefIds to AST items |
src/ident.rs | visit_scopes, resolve_ident_in_lexical_scope: core lookup algorithms |
src/late.rs | LateResolutionVisitor, Rib, RibKind, lifetime resolution |
src/diagnostics.rs | Resolution error diagnostics and import suggestions |
src/late/diagnostics.rs | Late-resolution-specific error detail and suggestions |
src/check_unused.rs | UnusedImportCheckVisitor: unused use and extern crate lints |
src/effective_visibilities.rs | EffectiveVisibilitiesVisitor: computes pub effective visibility |
Sources: compiler/rustc_resolve/src/lib.rs83-93
Resolution is independent across three namespaces. Many lookups must check all three via PerNS<T>.
| Namespace | Constant | Contains |
|---|---|---|
| Type | TypeNS | Modules, types, traits, type aliases, type parameters |
| Value | ValueNS | Functions, statics, consts, locals, enum constructors |
| Macro | MacroNS | macro_rules! macros, proc-macros, built-in attributes |
Sources: compiler/rustc_resolve/src/lib.rs57-61
A "module" in rustc_resolve is broader than a mod item. ModuleData<'ra> represents any item with its own namespace scope. Module<'ra> is an interned (pointer-comparable) reference to it.
Module tree structure:
ModuleKind variant | Rust construct |
|---|---|
Block | A braced block containing items |
Def(DefKind::Mod, ...) | A mod foo {} item or the crate root |
Def(DefKind::Enum, ...) | An enum (holds variant constructors) |
Def(DefKind::Trait, ...) | A trait (holds associated items) |
Sources: compiler/rustc_resolve/src/lib.rs512-828
Every named item, import, or macro definition is represented as Decl<'ra> (an interned DeclData<'ra>).
DeclKind::Import forms a linked chain: each re-export points to its source. Walking to the end of the chain finds the originating Def.
Sources: compiler/rustc_resolve/src/lib.rs846-893
NameResolution<'ra> holds the current state for a single (module, name, namespace) triple:
| Field | Meaning |
|---|---|
non_glob_decl | The unique non-glob binding for this name, if resolved |
glob_decl | The best glob-imported binding, if any |
single_imports | Set of pending single-import Imports that may define this name |
BindingKey indexes into a module's lazy_resolutions map:
BindingKey { ident: IdentKey, ns: Namespace, disambiguator: u32 }
IdentKey pairs a Symbol with a Macros20NormalizedSyntaxContext (hygiene context). This normalization is the basis for macro hygiene: identifiers introduced by different macro expansions get different contexts and do not collide unless hygiene allows it.
Sources: compiler/rustc_resolve/src/imports.rs242-273 compiler/rustc_resolve/src/lib.rs549-587
ImportData<'ra> carries all metadata for a use item.
ImportKind variant | Source syntax |
|---|---|
Single { source, target, ... } | use foo::bar or use foo::bar as baz |
Glob { ... } | use foo::* |
ExternCrate { source, target, ... } | extern crate foo |
MacroUse { ... } | #[macro_use] extern crate foo |
MacroExport | #[macro_export] macro_rules! foo |
Import<'ra> is an interned reference to ImportData<'ra>, similar to Module<'ra> and Decl<'ra>.
Sources: compiler/rustc_resolve/src/imports.rs62-105
The resolution pipeline has two top-level stages: early resolution (interleaved with macro expansion) and late resolution (after full expansion).
Overall pipeline:
ResolverExpand TraitThe expander in rustc_expand drives the loop. It interacts with rustc_resolve through the ResolverExpand trait, which Resolver<'ra, 'tcx> implements in macros.rs.
Key methods the expander calls on Resolver:
| Method | Called when |
|---|---|
resolve_macro_invocation() | Expander encounters a macro call site |
visit_ast_fragment_with_placeholders() | Expander finishes expanding one macro |
resolve_imports() | After integrating a fragment, to make import progress |
expansion_for_ast_pass() | Registering a built-in AST transformation pass |
resolve_dollar_crates() | Updating $crate hygiene contexts |
Sources: compiler/rustc_resolve/src/macros.rs168-254
Every time a new AST fragment is produced (including the initial crate), collect_definitions in def_collector.rs assigns a LocalDefId to each item-level node. DefCollector is an AST visitor that calls Resolver::create_def for each item kind, tracking the parent LocalDefId through the tree.
Notably, collect_definitions is called inside build_reduced_graph—it runs as the first step of integrating every new fragment.
Sources: compiler/rustc_resolve/src/def_collector.rs18-60 compiler/rustc_resolve/src/build_reduced_graph.rs243-244
After each macro expansion, Resolver::visit_ast_fragment_with_placeholders calls build_reduced_graph. The BuildReducedGraphVisitor walks the new fragment and:
plant_decl_into_local_module for each item to register it in its module's lazy_resolutionsImport entries to the import queue for each use statementunexpanded_invocations setMacroRulesScopeRef to track macro_rules! chainsFor items from external crates, build_reduced_graph_external lazily populates a module from CStore metadata the first time it is accessed.
Sources: compiler/rustc_resolve/src/build_reduced_graph.rs239-267 compiler/rustc_resolve/src/macros.rs195-212
Import resolution is iterative and runs after each call to build_reduced_graph. The resolver attempts to make progress on all pending imports:
source in the target module. If found, create a Decl of DeclKind::Import pointing to the source declaration and plant it in the importing module.glob_decl entries in the importing module (lower priority than non-glob bindings).An import may return Determinacy::Undetermined if its target has not yet been resolved (e.g., a glob over a module defined by a pending use). The loop continues until no import changes state (either all resolved or all stuck on genuine errors).
Sources: compiler/rustc_resolve/src/imports.rs324
resolve_macro_invocation is called by the expander for each macro call site. It:
MacroNS for the macro pathOk(Arc<SyntaxExtension>) if foundErr(Indeterminate) if a pending import could still bring the macro into scope, asking the expander to retry laterMacroRulesScope tracks the textual scope of macro_rules! definitions. It forms a linked list used during scope search:
MacroRulesScope variant | Meaning |
|---|---|
Empty | Root of the chain; no macro_rules! names visible here |
Def(&MacroRulesDecl) | A macro_rules! definition is in scope here |
Invocation(LocalExpnId) | A macro invocation that could produce new macro_rules! definitions |
Path compression is applied to Invocation nodes once their expansion is known, preventing scope chains from growing unboundedly.
Sources: compiler/rustc_resolve/src/macros.rs52-104 compiler/rustc_resolve/src/macros.rs256
After the crate is fully expanded, LateResolutionVisitor in late.rs walks the entire expanded AST to resolve all remaining names: expressions, types, patterns, labels, and lifetimes. It implements Visitor<'ast> and uses the rib stack for lexical scope tracking (see Rib System).
Sources: compiler/rustc_resolve/src/late.rs799-812
When resolving a name, visit_scopes in ident.rs searches through Scope enum variants in priority order. The starting scope and traversal order depend on the namespace.
Scope chain priority by namespace:
The ModuleNonGlobs/ModuleGlobs step loops through hygienic lexical parents via hygienic_lexical_parent, which walks up both the lexical module tree and the expansion context tree simultaneously.
ScopeSet controls which subset of scopes is visited for a given lookup (e.g., ScopeSet::Module restricts to a single module; ScopeSet::Macro(MacroKind) restricts to MacroNS with a kind filter).
Non-glob bindings always beat glob bindings. Among glob bindings, ambiguities are detected and recorded as AmbiguityError entries.
Sources: compiler/rustc_resolve/src/ident.rs50-238 compiler/rustc_resolve/src/lib.rs111-161
For late resolution (after full expansion), names are looked up through a rib stack before falling back to the module-level scope chain. A rib is a single local scope.
LateResolutionVisitor maintains:
ribs: PerNS<Vec<Rib<'ra>>> — three stacks (TypeNS, ValueNS, MacroNS)label_ribs: Vec<Rib<'ra, NodeId>> — loop label scopeslifetime_ribs: Vec<LifetimeRib> — lifetime parameter scopesRib<'ra> holds:
bindings: FxIndexMap<Ident, Res> — names bound in this scopekind: RibKind<'ra> — governs whether outer ribs are accessibleRib kinds and their access rules:
RibKind variant | Introduces | Restricts outer access |
|---|---|---|
Normal | Local let bindings, fn params | None |
Block(Option<Module>) | Block-scoped items | None |
FnOrCoroutine | — | Blocks label resolution across fn boundary |
Item(HasGenericParams, DefKind) | Generic params | Blocks upvalue locals |
ConstantItem(ConstantHasGenerics, ...) | — | Blocks generics (except in trivial positions) |
Module(Module) | — | Triggers module-level visit_scopes lookup |
MacroDefinition(DefId) | — | Hygiene barrier for macro_rules! |
ForwardGenericParamBan(...) | — | Forbids forward-referenced generic params |
AssocItem | — | Restricts to enclosing trait/impl generics |
ConstParamTy | — | Forbids all generic params |
InlineAsmSym | — | Allows only global (non-local) names |
Rib search process:
Sources: compiler/rustc_resolve/src/late.rs280-307 compiler/rustc_resolve/src/ident.rs304-383
Lifetimes use a parallel lifetime_ribs: Vec<LifetimeRib> stack with LifetimeRibKind:
LifetimeRibKind variant | Purpose |
|---|---|
Generics { binder, span, kind } | Introduces named lifetime params; only kind with non-empty bindings |
AnonymousCreateParameter | Creates a fresh anonymous '_ parameter for &T syntax |
Elided(LifetimeRes) | Replaces all '_ occurrences with the given resolution |
AnonymousReportError | Emits an error when '_ is used in forbidden positions |
ConcreteAnonConst(reason) | Forbids lifetime params in anon const positions |
Item | Barrier: prevents referring to outer item's lifetimes |
StaticIfNoLifetimeInScope | 'static elision fallback for older code |
Sources: compiler/rustc_resolve/src/late.rs316-419
Every Ident in the AST carries a SyntaxContext (part of its Span) tracking which macro expansion introduced it. The resolver uses IdentKey as the lookup key in resolution maps, which normalizes this context to Macros20NormalizedSyntaxContext.
The two hygiene models in use:
macro_rules! hygiene (call-site transparency): macro_rules! items see the call site's context, but cannot accidentally capture caller names.macro proc-macros and procedural macros use the definition site; identifiers generated by the macro are opaque to the call site.hygienic_lexical_parent in ident.rs implements the scope traversal for hygiene: when the current module's expansion context is not a descendant of the current hygiene context, the resolver "peels off" one context layer and jumps to the module where that expansion was defined.
Sources: compiler/rustc_resolve/src/lib.rs549-587 compiler/rustc_resolve/src/ident.rs240-285
The Resolver accumulates the following maps that are consumed by later compiler phases:
| Map | Key → Value | Consumer |
|---|---|---|
partial_res_map | NodeId → PartialRes | HIR lowering: maps each path node to DefId or partial resolution |
import_res_map | NodeId → PerNS<Option<Res>> | HIR lowering: maps import nodes to their resolved definitions |
label_res_map | NodeId → NodeId | HIR lowering: maps break/continue to their target label |
lifetimes_res_map | NodeId → LifetimeRes | HIR lowering: maps lifetime uses to their declarations |
effective_visibilities | LocalDefId → EffectiveVisibility | Privacy checking (rustc_privacy) |
used_imports | FxHashSet<NodeId> | check_unused lint |
maybe_unused_trait_imports | FxIndexSet<LocalDefId> | Method resolution in rustc_hir_analysis |
These outputs are accessed by other crates through the ResolverAstLowering and ResolverGlobalCtxt traits defined in rustc_middle::ty.
Data flow from Resolver to downstream crates:
Sources: compiler/rustc_resolve/src/lib.rs69-73
Resolution errors fall into several categories, each with its own reporting path:
| Error category | Type / location | Notes |
|---|---|---|
| Unresolved name | ResolutionError::FailedToResolve | Reports candidates and typo suggestions |
| Ambiguous name | AmbiguityError + AmbiguityKind | May be a lint or a hard error |
| Privacy violation | PrivacyError | Deduped by span before emission |
| Duplicate definition | — | Reported via report_conflict in diagnostics.rs |
| Unused import | — | check_unused.rs, buffered as lints |
| Unused qualifications | — | UNUSED_QUALIFICATIONS lint from late resolution |
AmbiguityKind values identify the specific kind of conflict:
| Variant | Conflict type |
|---|---|
GlobVsGlob | Two glob imports bring in the same name |
GlobVsOuter | Glob binding shadows an outer scope binding |
GlobVsExpanded | Glob binding conflicts with a macro-expanded name |
MacroRulesVsModularized | macro_rules! name conflicts with a module-path macro |
BuiltinAttr | Name conflicts with a built-in attribute |
DeriveHelper | Name conflicts with a derive helper attribute |
MoreExpandedVsOuter | Macro-expanded name conflicts with less-expanded outer scope |
Some AmbiguityErrors are reported as lints (AMBIGUOUS_GLOB_IMPORTS, AMBIGUOUS_GLOB_REEXPORTS) rather than hard errors for backwards compatibility.
Sources: compiler/rustc_resolve/src/lib.rs924-972 compiler/rustc_resolve/src/diagnostics.rs126-165
Refresh this wiki
This wiki was recently refreshed. Please wait 4 days to refresh again.