src/doc/rustc-dev-guide/src/name-resolution.md MARKDOWN 213 lines View on github.com → Search inside
1# Name resolution23In the previous chapters, we saw how the [*Abstract Syntax Tree* (`AST`)][ast]4is built with all macros expanded.5We saw how doing that requires doing some6name resolution to resolve imports and macro names.7In this chapter, we show how this is actually done and more.89[ast]: ./ast-validation.md1011In fact, we don't do full name resolution during macro expansion -- we only12resolve imports and macros at that time.13This is required to know what to even expand.14Later, after we have the whole AST, we do full name resolution to15resolve all names in the crate.16This happens in [`rustc_resolve::late`][late].17Unlike during macro expansion, in this late expansion, we only need to try to18resolve a name once, since no new names can be added.19If we fail to resolve a name, then it is a compiler error.2021Name resolution is complex. There are different namespaces (e.g.22macros, values, types, lifetimes), and names may be valid at different (nested)23scopes.24Also, different types of names can fail resolution differently, and25failures can happen differently at different scopes.26For example, in a module scope,27failure means no unexpanded macros and no unresolved glob imports in28that module.29On the other hand, in a function body scope, failure requires that a30name be absent from the block we are in, all outer scopes, and the global scope.3132[late]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/index.html3334## Basics3536In our programs we refer to variables, types, functions, etc, by giving them37a name.38These names are not always unique.39For example, take this valid Rust program:4041```rust42type x = u32;43let x: x = 1;44let y: x = 2;45```4647How do we know on line 3 whether `x` is a type (`u32`) or a value (1)?48These conflicts are resolved during name resolution.49In this specific case,50name resolution defines that type names and variable names live in separate51namespaces and therefore can co-exist.5253The name resolution in Rust is a two-phase process.54In the first phase,55which runs during `macro` expansion,56we build a tree of modules and resolve imports.57Macro expansion and name resolution communicate with each other via the58[`ResolverAstLoweringExt`] trait.5960The input to the second phase is the syntax tree, produced by parsing input61files and expanding `macros`.62This phase produces links from all the names in the63source to relevant places where the name was introduced.64It also generates helpful error messages,65like typo suggestions, traits to import, or lints about unused items.6667A successful run of the second phase ([`Resolver::resolve_crate`]) creates kind68of an index the rest of the compilation may use to ask about the present names69(through the `hir::lowering::Resolver` interface).7071The name resolution lives in the [`rustc_resolve`] crate, with the bulk in72`lib.rs` and some helpers or symbol-type specific logic in the other modules.7374[`Resolver::resolve_crate`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/struct.Resolver.html#method.resolve_crate75[`ResolverAstLoweringExt`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast_lowering/trait.ResolverAstLoweringExt.html76[`rustc_resolve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/index.html7778## Namespaces7980Different kind of symbols live in different namespaces  e.g. types don't81clash with variables.82This usually doesn't happen, because variables start with83lower-case letter while types with upper-case one, but this is only a84convention.85This is legal Rust code that will compile (with warnings):8687```rust88type x = u32;89let x: x = 1;90let y: x = 2; // See? x is still a type here.91```9293To cope with this, and with slightly different scoping rules for these94namespaces, the resolver keeps them separated and builds separate structures for95them.9697In other words, when the code talks about namespaces, it doesn't mean the module98hierarchy, it's types versus values versus macros.99100## Scopes and ribs101102A name is visible only in certain area in the source code.103This forms a hierarchical structure,104but not necessarily a simple one  if one scope is105part of another, it doesn't mean a name visible in the outer scope is also106visible in the inner scope, or that it refers to the same thing.107108To cope with that, the compiler introduces the concept of [`Rib`]s.109This is an abstraction of a scope.110Every time the set of visible names potentially changes,111a new [`Rib`] is pushed onto a stack.112The places where this can happen include for example:113114[`Rib`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.Rib.html115116* The obvious places  curly braces enclosing a block, function boundaries,117  modules.118* Introducing a `let` binding  this can shadow another binding with the same119  name.120* Macro expansion border  to cope with macro hygiene.121122When searching for a name, the stack of [`ribs`] is traversed from the innermost123outwards.124This helps to find the closest meaning of the name (the one not125shadowed by anything else).126The transition to outer [`Rib`] may also affect127what names are usable  if there are nested functions (not closures),128the inner one can't access parameters and local bindings of the outer one,129even though they should be visible by ordinary scoping rules.130An example:131132[`ribs`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/late/struct.LateResolutionVisitor.html#structfield.ribs133134```rust135fn do_something<T: Default>(val: T) { // <- New rib in both types and values (1)136    // `val` is accessible, as is the helper function137    // `T` is accessible138   let helper = || { // New rib on the block (2)139        // `val` is accessible here140    }; // End of (2), new rib on `helper` (3)141    // `val` is accessible, `helper` variable shadows `helper` function142    fn helper() { // <- New rib in both types and values (4)143        // `val` is not accessible here, (4) is not transparent for locals144        // `T` is not accessible here145    } // End of (4)146    let val = T::default(); // New rib (5)147    // `val` is the variable, not the parameter here148} // End of (5), (3) and (1)149```150151Because the rules for different namespaces are a bit different, each namespace152has its own independent [`Rib`] stack that is constructed in parallel to the others.153In addition, there's also a [`Rib`] stack for local labels (e.g. names of loops or154blocks), which isn't a full namespace in its own right.155156## Overall strategy157158To perform the name resolution of the whole crate, the syntax tree is traversed159top-down and every encountered name is resolved.160This works for most kinds of names,161because at the point of use of a name it is already introduced in the [`Rib`]162hierarchy.163164There are some exceptions to this.165Items are bit tricky, because they can be166used even before encountered  therefore every block needs to be first scanned167for items to fill in its [`Rib`].168169Other, even more problematic ones, are imports which need recursive fixed-point170resolution and macros, that need to be resolved and expanded before the rest of171the code can be processed.172173Therefore, the resolution is performed in multiple stages.174175## Speculative crate loading176177To give useful errors, rustc suggests importing paths into scope if they're178not found.179How does it do this?180It looks through every module of every crate and looks for possible matches.181This even includes crates that haven't yet been loaded!182183Eagerly loading crates to include import suggestions that haven't yet been184loaded is called _speculative crate loading_, because any errors it encounters185shouldn't be reported: [`rustc_resolve`] decided to load them, not the user.186The function that does this is [`lookup_import_candidates`] and lives in187[`rustc_resolve::diagnostics`].188189[`rustc_resolve`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/index.html190[`lookup_import_candidates`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/struct.Resolver.html#method.lookup_import_candidates191[`rustc_resolve::diagnostics`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_resolve/diagnostics/index.html192193To tell the difference between speculative loads and loads initiated by the194user, [`rustc_resolve`] passes around a `record_used` parameter, which is `false` when195the load is speculative.196197## TODO: [#16](https://github.com/rust-lang/rustc-dev-guide/issues/16)198199This is a result of the first pass of learning the code.200It is definitely incomplete and not detailed enough.201It also might be inaccurate in places.202Still, it probably provides useful first guidepost to what happens in there.203204* What exactly does it link to and how is that published and consumed by205  following stages of compilation?206* Who calls it and how it is actually used.207* Is it a pass and then the result is only used, or can it be computed208  incrementally?209* The overall strategy description is a bit vague.210* Where does the name `Rib` come from?211* Does this thing have its own tests, or is it tested only as part of some e2e212  testing?

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.