Name resolution
Name resolution is the process of tying paths and other identifiers to the declarations of those entities. Names are segregated into different namespaces, allowing entities in different namespaces to share the same name without conflict. Each name is valid within a scope, or a region of source text where that name may be referenced. Access to a name may be restricted based on its visibility.
Name resolution is split into three stages throughout the compilation process. The first stage, expansion-time resolution, resolves all use declarations and macro invocations. The second stage, primary resolution, resolves all names that have not yet been resolved and that do not depend on type information to resolve. The last stage, type-relative resolution, resolves the remaining names once type information is available.
Note
Expansion-time resolution is also known as early resolution. Primary resolution is also known as late resolution.
General
The rules within this section apply to all stages of name resolution.
Scopes
Note
This is a placeholder for future expansion about resolution of names within various scopes.
Expansion-time name resolution
Expansion-time name resolution is the stage of name resolution necessary to complete macro expansion and fully generate a crate's AST. This stage requires the resolution of macro invocations and use declarations. Resolving use declarations is required for macro invocations that resolve via path-based scope. Resolving macro invocations is required in order to expand them.
After expansion-time name resolution, the AST must not contain any unexpanded macro invocations. Every macro invocation resolves to a valid definition that exists in the final AST or in an external crate.
m!; // ERROR: Cannot find macro `m` in this scope.
The resolution of names must be stable. After expansion, names in the fully expanded AST must resolve to the same definition regardless of the order in which macros are expanded and imports are resolved.
All name resolution candidates selected during macro expansion are considered speculative. Once the crate has been fully expanded, all speculative import resolutions are validated to ensure that macro expansion did not introduce any new ambiguities.
Note
Due to the iterative nature of macro expansion, this causes so-called time traveling ambiguities, such as when a macro or glob import introduces an item that is ambiguous with its own base path.
# f!; const _: = ;
Imports
All use declarations are fully resolved during this stage of resolution. Type-relative paths cannot be resolved at this stage and will produce an error.
// Valid imports resolved at expansion-time:
use C; // OK.
use E; // OK.
use A; // OK.
use V; // OK.
// Valid expressions resolved during type-relative resolution:
let _ = V; // OK.
let _ = C; // OK.
#
// Invalid type-relative imports that can't resolve at expansion-time:
use V; // ERROR: Unresolved import `m::A::V`.
use C; // ERROR: Unresolved import `m::E::C`.
Names introduced via use declarations in an outer scope are shadowed by candidates in the same namespace with the same name from an inner scope except where otherwise restricted by name resolution ambiguities.
// This introduces the name `ambig` in the outer scope.
use ambig;
const _: = ;
Shadowing of names introduced via use declarations within a single scope is permitted in the following situations:
Ambiguities
There are certain situations during expansion-time resolution where there are multiple macro definitions, use declarations, or modules an import or macro invocation's name could refer to where the compiler cannot consistently determine which candidate should shadow the other. Shadowing cannot be permitted in these situations and the compiler instead emits ambiguity errors.
Names may not be resolved through ambiguous glob imports. Glob imports are allowed to import conflicting names in the same namespace as long as the name is not used. Names with conflicting candidates from ambiguous glob imports may still be shadowed by non-glob imports and used without producing an error. The errors occur at time of use, not time of import.
// OK: This brings conficting names in the same namespace into scope
// but they have not been used yet.
use *;
use *;
const _: = ;
#
#
#
#
# use *;
# use *; // OK: No name conflict.
const _: = ;
Multiple glob imports are allowed to import the same name, and that name is allowed to be used if the imports are of the same item (following reexports). The visibility of the name is the maximum visibility of the imports.
const _: = ;
#
Names in imports and macro invocations may not be resolved through glob imports when there is another candidate available in an outer scope.
Note
When one of [
core::panic!] or [std::panic!] is brought into scope due to the standard library prelude, and a user-written glob import brings the other into scope,rustccurrently allows use ofpanic!, even though it is ambiguous. The user-written glob import takes precedence to resolve this ambiguity.In Rust 2021 and later, [
core::panic!] and [std::panic!] operate identically. But in earlier editions, they differ; only [std::panic!] accepts a [String] as the format argument.E.g., this is an error:
extern crate core; use *;And this is accepted:
extern crate std; use *;Don't rely on this behavior; the plan is to remove it.
For details, see Rust issue #147319.
// Outer `ambig` candidate.
const _: = ;
// As above, but with macros.
use f as ambig;
const _: = ;
Note
These ambiguity errors are specific to expansion-time resolution. Having multiple candidates available for a given name during later stages of resolution is not considered an error. So long as none of the imports themselves are ambiguous, there will always be a single unambiguous closest resolution.
use AMBIG; const C: = ;
Names may not be resolved through ambiguous macro reexports. Macro reexports are ambiguous when they would shadow a textual macro candidate for the same name in an outer scope.
// Textual macro candidate.
// Path-based macro candidate.
Note
This restriction is needed due to implementation details in the compiler, specifically the current scope visitation logic and the complexity of supporting this behavior. This ambiguity error may be removed in the future.
Macros
Macros are resolved by iterating through the available scopes to find the available candidates. Macros are split into two sub-namespaces, one for function-like macros, and the other for attributes and derives. Resolution candidates from the incorrect sub-namespace are ignored.
The available scope kinds are visited in the following order. Each of these scope kinds represent one or more scopes.
- Derive helpers
- Textual scope macros
- Path-based scope macros
macro_useprelude- Standard library prelude
- Builtin attributes
Note
The compiler will attempt to resolve derive helpers that are used before their associated macro introduces them into scope. This scope is visited after the scope for resolving derive helper candidates that are correctly in scope. This behavior is slated for removal.
For more info see derive helper scope.
Note
This visitation order may change in the future, such as interleaving the visitation of textual and path-based scope candidates based on their lexical scopes.
2018 Edition differences
Starting in edition 2018 the
#[macro_use]prelude is not visited when#[no_implicit_prelude]is present.
The names cfg and cfg_attr are reserved in the macro attribute sub-namespace.
Ambiguities
Names may not be resolved through ambiguous candidates inside of macro expansions. Candidates inside of macro expansions are ambiguous when they would shadow a candidate for the same name from outside of the first candidate's macro expansion and the invocation of the name being resolved is also from outside of the first candidate's macro expansion.
// Introduce outer candidate definition for `ambig` macro invocation.
// Introduce a second candidate definition for `ambig` inside of a
// macro expansion.
define_ambig!;
// The definition of `ambig` from the second invocation
// of `define_ambig` is the innermost canadidate.
//
// The definition of `ambig` from the first invocation of
// `define_ambig` is the second candidate.
//
// The compiler checks that the first candidate is inside of a macro
// expansion, that the second candidate is not from within the same
// macro expansion, and that the name being resolved is not from
// within the same macro expansion.
ambig!; // ERROR: `ambig` is ambiguous.
The reverse is not considered ambiguous.
#
// Swap order of definitions.
define_ambig!;
// The innermost candidate is now less expanded so it may shadow more
// the macro expanded definition above it.
ambig!;
Nor is it ambiguous if the invocation being resolved is within the innermost candidate's expansion.
define_and_invoke_ambig!;
It doesn't matter if both definitions come from invocations of the same macro; the outermost candidate is still considered "less expanded" because it is not within the expansion containing the innermost candidate's definition.
#
define_ambig!;
define_ambig!;
ambig!; // ERROR: `ambig` is ambiguous.
This also applies to imports so long as the innermost candidate for the name is from within a macro expansion.
const _: = ;
User-defined attributes or derive macros may not shadow built-in non-macro attributes (e.g. inline).
// with-helper/src/lib.rs
# use TokenStream;
// ^^^^^^^^^^^^^^
// User-defined attribute candidate.
// ...
#
// src/lib.rs
// ERROR: `non_exhaustive` is ambiguous.
;
Note
This applies regardless of the name the built-in attribute is a candidate for:
// with-helper/src/lib.rs # use TokenStream; # // ^^^^^^ // User-defined attribute candidate. // ... #// src/lib.rs use inline as helper; // ^----- Built-in attribute candidate via reexport. // ERROR: `helper` is ambiguous. ;
Primary name resolution
Note
This is a placeholder for future expansion about primary name resolution.
Type-relative resolution
Note
This is a placeholder for future expansion about type-dependent resolution.