Skip to main content
v0.14.0

Name & Reference Resolution

The pipeline stage after module loading (Module Loading & Parsing): every top-level declaration across the loaded ModuleGraph gets a stable SymbolId, import/glob visibility is settled per module, and every reference site is classified against that symbol space. Owning crate: metel-frontend. Defined in name_resolver.rs, reference_resolver.rs, and symbols.rs.

This is adjacent to, but distinct from, Resolution (arch.resolution.*, ADR-0054's identity-freeze model in identity/). That section covers structural LocalId/RefId/FieldId/VariantId allocation for lexical bindings and member declarations. This section covers an earlier, different concern: binding a top-level declaration to a SymbolId, and classifying which references point at one. A reader should not conflate the two symbol/identity systems just because both produce stable ids.

Model​

Resolution begins by giving every declaration one canonical SymbolId; imports and aliases then point back to that declaration rather than minting local replacements (declaration identity). Import precedence is settled before reference classification, so explicit imports and globs behave predictably (import scopes).

Reference collection records the identity selected at each use site (references). Path normalization is a following, separate stage; both precede the structural identity freeze described in the Resolution section.

Verifiable architecture claims

Owner metel-frontend unless a requirement names another.

Requirement №1​

Every top-level declaration gets a SymbolId from one canonical SymbolTable: builtin std::core items at fixed SYM_* ids, user declarations from USER_SYM_START, and a separate range for overloads. The same declaration keeps one id under any importer, alias or resolution order.

Implemented by (2)
  • intern metel-frontend/src/identity/symbols.rs
  • new metel-frontend/src/identity/symbols.rs
Tested by (7)
Requirement №2​

An explicit import wins over a glob, and two explicit imports of one local name are an error. Globs are tiered: a user glob silently beats the auto-inserted std glob, and T0011 fires only when two globs of the same tier export the same name.

Implemented by (2)
  • add_explicit metel-frontend/src/pipeline/name_resolution/name_resolver/mod.rs
  • resolve_module metel-frontend/src/pipeline/name_resolution/name_resolver/mod.rs
Tested by (6)
Requirement №3​

Each bare-identifier reference is Res::Def (a top-level declaration, with its SymbolId) or Res::Local (parameter, let/mut, for or match binding); a local shadows a same-named global. Only Def references are recorded, keyed by Span, before the resolution freeze.

Implemented by (1)
Tested by (2)

Known limitations​

knownLIMIT-NAME-RESOLUTION-002 — Overload SymbolIds come from a process-global counter that is never reset. Free-function overload ids are allocated from a static counter shared by every compilation in the process, so their values depend on what was compiled before. Open record ↗knownLIMIT-NAME-RESOLUTION-003 — The SymbolId space is split between three allocators by convention, with no cross-check. User, overload and block-local ids share one u32 split into ranges by convention; nothing guards the boundaries or overflow, and the table's map is public. Open record ↗knownLIMIT-NAME-RESOLUTION-004 — Builtin SymbolIds are a hard-coded list of 21 names; other std declarations are numbered per program. Only 18 builtin types and 3 aspects have fixed ids, kept in Rust beside the std::core module file; every other std declaration gets an id from a per-program sorted pass. Open record ↗knownLIMIT-NAME-RESOLUTION-005 — Symbol identity is a (module, name-string) key, so distinct declarations can share one SymbolId. ResolvedNames.symbols keys ids by module path and a name string: every declaration kind shares that key space, and a method's key drops its impl's type arguments, so different impls collide. Open record ↗
Resolved (1)
resolvedLIMIT-NAME-RESOLUTION-001 — std::core had no physical module file (resolved by ADR-0039). std::core had no physical module file; resolved by ADR-0039. Open record ↗