Skip to content

Name resolution - #1

Closed
Y-Nak wants to merge 35 commits into
mainfrom
name-resolution
Closed

Name resolution#1
Y-Nak wants to merge 35 commits into
mainfrom
name-resolution

Conversation

@Y-Nak

@Y-Nak Y-Nak commented Jul 6, 2026

Copy link
Copy Markdown
Member

TBW...
Orchestration: Claude Fable 5 ultracode
Implementation: Codex 5.5 xhigh
Review: Claude Fable 5 ultracode + Codex 5.5 xhigh + @Y-Nak

Y-Nak and others added 30 commits February 23, 2026 12:52
`hir::anchor::def_locations_for_file` was `todo!()`, so any Def-anchored
span or diagnostic panicked; only Root-anchored parse errors resolved.
The table is produced by `parser::parse_file_to_hir` (which depends on
`hir`), so the resolver cannot live as a plain tracked fn in `hir`.

Add `Db::def_location_table` to `hir` and have the concrete databases
(`DriverDb`, test `TestDb`) implement it by delegating to the parser
(dependency injection, rust-analyzer `Upcast`-style). Resolution stays at
the diagnostic/LSP edge so anchor-relative spans keep the Salsa cache
byte-shift-invariant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Proves the core Salsa property: inserting a comment *above* a function
leaves the function's Def-anchored relative span byte-identical (so its
HIR node is unchanged and downstream queries can backdate), while
absolute resolution shifts by exactly the inserted length.

Expose `Module::items` so HIR consumers (this test, the coming
name-resolver and type-checker) can introspect a lowered module.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Carry parser recovery spans into HIR error nodes so LSP callers can ask for spans on malformed input without panicking. Also avoid corrupting spans when addition sees mismatched anchors, and preserve recovery spans for TypeRefKind::Error after verifying it was the remaining HIR span panic.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an event-logging Salsa test DB and a semantic-style tracked query that reads only Def-anchored relative span offsets. The test proves edits above the function leave the query result unchanged and do not re-execute it, while absolute resolution still shifts at the edge.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DefId keys now include container ownership and an optional syntactic fingerprint so methods and instances are identified by structure instead of encounter order. This keeps disambiguators for actual key collisions while preserving diagnostic key round-tripping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Cover container-relative methods, instance head fingerprints, edit-stable identities, and zero disambiguators for a well-formed program so future lowering changes cannot silently reintroduce encounter-order identity.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Instance DefIds now fingerprint the full predicate head by length-prefixing the canonical subject type and class arguments. Import DefIds now use a canonical import fingerprint so unrelated imports no longer shift identities.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Catch the parser up to current experimental syntax. Contract members may
carry `public` and/or `payable` (in that order); both are rejected on
free functions with a clear diagnostic (recovering so parsing continues).
Add `constructor(...)` and `fallback(...)` contract members via a new
`FuncKind`, and thread `public`/`payable` spans into `FuncSig`.

Lifts current-corpus parse coverage from 166 to 270 files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Accept the contextual `comptime` keyword in type position
(`TypeRefKind::Comptime`), parameter position, and `let x : comptime T`,
recording keyword spans in the HIR. Comptime *evaluation* semantics are a
later phase; this only lets current-syntax sources parse. `comptime`
stays a valid identifier/type name where it is not a modifier.

Lifts current-corpus parse coverage from 270 to 286 files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the stale `import path { a, b }` form with the current syntax:
selective `import mod.{A, B}`, wildcard `import mod.{*}`, per-name
`{X as Y}` aliases, a trailing `hiding { ... }` clause, operator-symbol
selectors like `(^^)`, and top-level `export { ... };`. Model these in
the HIR (`ImportSelector`, `SelectedName`, `hiding`, `Export`) and update
the import DefId fingerprint so structurally distinct imports keep
order-independent identities.

Atomic grammar change (HIR signature + parser + lowering + fingerprint);
the two touched `.snap`s reflect the new expected-token set, not a
regression. Lifts current-corpus parse coverage from 286 to 398 files.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Multi-element tuple types and expressions previously lowered to silent
`Error` nodes. Represent tuples n-ary at the SAIL level: `TypeRefKind::Tuple`
holds `Vec<TypeRef>`, add `ExprKind::Tuple`, with arity rules `()` -> unit
(empty tuple), `(T)` -> grouping, `(A, B, ...)` -> n-ary. The shared
`lower_type_list_ref` also fixes multi-field data constructors
(`data P = P(a, b)`), which no longer lower to `Error`. (Hull's
right-nested-pair encoding is deferred to the backend.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adversarial review found two fidelity gaps vs the reference grammar:
- `constructor`/`fallback` only accept `payable` (not `public`, which is
  implicit); `fallback` must declare no parameters and return unit. Emit
  targeted, recovering diagnostics for each. The negative corpus files
  `public-constructor.solc`/`public-fallback.solc` now correctly fail.
- A parenthesized single pattern `(p)` is grouping, not a 1-tuple —
  mirror the tuple type/expr arity rule in pattern lowering.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`match` constructor patterns may be qualified by their type name
(`Option.None`, `Option.Some(x)`), nested arbitrarily. Add an optional
`qualifier` to `PatKind::Ctor` (resolved later by name resolution) and
parse `Type.Ctor` / `Type.Ctor(args)`; bare lowercase names remain
variable patterns.

Lifts current-corpus parse coverage from 394 to 460 files (80%).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Support the functional-style forms: a bare expression is a statement
(optional trailing `;`, matching the reference `StmtExp <$ optional
semicolon`), so `function zero() { 0 }` and `{ f(x) }` bodies parse;
assignments still require `;`. Add the `if e1 then e2 else e3`
expression, with `then` demoted from a keyword to a contextual token so
it stays usable as an identifier.

Lifts current-corpus parse coverage from 460 to 480 files (83.5%).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add the reference's remaining statement/pattern forms: leading-dot
constructors `.Ctor(args)` in expression and pattern position (type
inferred from context), `for(init; cond; post)` statements plus
`break;`/`continue;`, tolerated trailing `;` after `match { ... }`
(the old fail fixture moves to ok), and `comptime EXPR` match labels
stored via the expression arena.

Lifts current-corpus parse coverage from 480 to 512 files (89%).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Type references may be qualified by a module/alias segment
(`TypeRefKind::Named` gains a `qualifier`, resolved later by name
resolution). Import paths may start with `@lib` marking an external
library root (recorded on the HIR Import and folded into the identity
fingerprint), and `@T` in type position desugars to `Proxy(T)` per the
reference grammar. The invalid-token fixtures switch to `~` now that
`@` lexes.

With the dot-constructor work this lifts current-corpus parse coverage
to 533 files (93%).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`data` declarations may omit the trailing `;` at declaration boundaries,
matching the reference. Exports gain the module forms (`export mod;`,
`export mod as M;`, `export mod.{items};`) and both import/export
selector lists accept constructor selectors (`T(*)`, `T(A, B)`),
modeled in the HIR and folded into the identity fingerprints.

Resolved against the qualified-import work: external `@` marker plus
selector/hiding both feed the import fingerprint.

Lifts current-corpus parse coverage to 551 files (95.8%).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add `&`, `^`, `|` (guarded against match-arm `|`), `%` to the expression
precedence ladder matching the reference (`* / %`, `+ -`, `&`, `^`, `|`,
relational, equality, `&&`, `||`), plus the `%=`, `&=`, `|=`, `^=`
compound assignments.

Integrating this against the comptime-match-label work created a
construction-time cycle (`expr -> pat` via the match-arm guard,
`pat -> expr` via comptime labels) that overflowed the stack on any
parse; the expression and pattern parsers are now built together via
`Recursive::declare`/`define` so the mutual reference is resolved at
parse time.

Lifts current-corpus parse coverage to 555 files (96.5%).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Final parser sweep against the reference corpus: qualified types and
constructor patterns now take arbitrary-depth qualifiers
(`mod.Type.Ctor`), import selector lists may mix `*` with names,
`@T`/`@(T, U)` proxy sugar works in expression annotations, and match
arm bodies accept block statements.

Every remaining corpus failure (13 files) is now a confirmed negative —
inputs the reference parser also rejects (contract-only modifiers,
fallback arity/return rules, selector alias tails, missing data/class
`;`). Parse acceptance: 562/575, full parity with the reference.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the stale ported fixtures with the current experimental corpus
(562 parse-ok / 13 reference-rejected files, structure preserved) and
tighten the ok-fixture contract: a file passes only with zero
diagnostics AND zero Error nodes anywhere in the lowered HIR
(hir::visit::collect_error_nodes), so silent lowering gaps can no
longer masquerade as coverage. All 562 vendored ok files satisfy the
stricter check. Five parse-clean semantic-diagnostic fixtures wait in
corpus/known-diagnostic-gaps/ until type checking exists.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy std/*.solc from the argotorg/solcore snapshot as the
compiler-bundled library root for the coming module loader; README
records provenance.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
New `nameres` crate with logical module identity
(`ModuleId { library: Main|Std|External, path }` — never physical
paths), reference-faithful path resolution (relative, `lib.`-rooted,
`std` mapping, `@ext` external roots), a module graph with legal import
cycles, and `public_interface` computed as a fixed point via salsa 0.25
cycle recovery (`cycle_fn`/`cycle_initial`) to support recursive
modules. Import/export validation covers the reference diagnostic
catalog (SC0109-SC0120): opaque-by-default data exports, `T(*)`/`T(A,B)`
constructor visibility, module re-exports, hiding, and
ambiguity/duplicate rules. The driver loads reachable modules from the
entry file with the vendored `std/` as the std root.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`hir::nameres` implements the reference two-namespace model (types =
contracts/data/aliases/classes; terms = functions + qualified
`Type.Ctor`; fields and module qualifiers separate) with SC0108
duplicate diagnostics, a builtin env mirroring the primitives (word,
bool, string, unit, pair, sum, integer, the reserved `Int` class), and
a per-body resolver honoring the reference scoping rules: params before
body, let-initializers before their binder, match-arm/lambda/block
scopes, `for` deliberately not scoping, locals shadowing fields and
fields beating same-name functions. Bare constructors report SC0106,
`.Ctor` defers to inference, and module-qualified names produce
placeholder resolutions for the cross-module pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`module_env` combines a module's own item scope with imports resolved
against exporters' public interfaces (per-name aliases, hiding, hidden
constructors invisible with partial-data metadata retained, local vs
import conflicts enforced, instances flowing independently of exports).
The body resolver's import hook and the deferred module-qualified
markers now resolve through it — `alias.name`, `alias.Type.Ctor`,
imported `Class.method`, nested re-export qualifiers — and the driver
renders full name-resolution diagnostics after loading.

Validated against the reference imports corpus with expectations from
the Haskell test suite: 58/58 expected-pass, 32/36 expected-fail; the
4 divergences are later-phase checks (match exhaustiveness, symlink
type identity, typechecked private helpers, pragma validation),
recorded as known divergences in the test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
salsa 0.25 -> 0.27.2 (no API fallout for our tracked/interned/
accumulator/cycle-recovery usage), compatible bumps across the tree
(annotate-snippets 0.12.16, insta 1.48, url 2.5.8). chumsky stays on
the 0.12 stable line — 1.0.0-alpha is a pre-release and not production
material. Add rustc-hash to the workspace for the FxHash unification.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace std HashMap/HashSet with FxHashMap/FxHashSet across the tree
(the compiler-standard fast non-cryptographic hasher). While auditing
iteration sites, make diagnostic emission order deterministic: sort
ambiguous-import groups, duplicate-export groups, and duplicate module
aliases before emitting. DefLocationTable keeps intentional std SipHash
(stability), ordering-sensitive surfaces keep BTreeMap/BTreeSet.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comments-only pass: module overviews and real doc comments for the
anchor-relative span system (why backdating works, the edge-only
absolute-resolution rule), structural DefId identity (owner chains,
fingerprints, duplicate-only disambiguators), lifetime-free diagnostic
label snapshots, the two-namespace scoping model and its reference
rules, the logical ModuleId + salsa-fixpoint public interfaces, the
expr/pat mutual recursion, and the silent-Error visitor contract.
cargo doc builds warning-free.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diagnostics are now first-class query values instead of salsa
accumulator side effects (the RA model): typed `NameresDiagnostic`
(SC0101-0108) and `ModuleDiagnostic` (SC0109-0120) enums lower to the
generic user-facing diagnostic at the edge, parser diagnostics flow
through `parse_diagnostics(file)`, and `module_diagnostics`/
`reachable_diagnostics` aggregate sorted and deduped (`DiagnosticId`).
This gives LSP-ready per-file grouping with deterministic order, no
demand-order dependence, and no side-effect coupling with fixpoint
queries. A `Suggestion`/`AnchoredTextEdit` surface is reserved for
future quickfixes. The lifetime-free LabelSpan snapshots and edge-only
absolute resolution are unchanged — query-level sort keys deliberately
avoid absolute offsets; position ordering happens at the render edge.
The accumulator path is fully removed; rendered output is
byte-identical (no snapshot changes).

Atomic API migration across hir/parser/nameres/driver.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
An audit confirmed parser recovery cascaded into garbage diagnostics:
every probe (lost signatures, broken imports/types/contract members)
reported spurious SC0101/SC0103 alongside the parse error, and a
parse-broken provider caused importer-side SC0101/SC0110 blame.

Policy now implemented and locked by tests: recovered Error nodes
resolve to Resolution::Err silently; a file with parse errors publishes
only its parse diagnostics (all nameres kinds suppressed — recovered
item boundaries are unreliable, matching the reference which never
shows nameres errors alongside parse errors); parse-broken providers
are treated as unknown interfaces so importers are not blamed for
absence. Parse-clean files keep full diagnostics (positive control).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Y-Nak and others added 5 commits July 6, 2026 23:05
Multiple reports ran together (next headline glued to the previous
snippet's last line). The driver now normalizes each rendered
diagnostic to exactly one trailing newline and prints a blank line
between consecutive reports, rustc-style.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Resolve the recorded over-invalidation finding: module_diagnostics now
aggregates a tracked per-body body_diagnostics query, so a body edit
that leaves diagnostics unchanged re-executes only the per-body query
and the module-level aggregation is backdated. Parse-error suppression
stays at the module boundary. The finding regression test is
un-ignored and asserts the new behavior.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Parser/lexer (lens 1/3): lambda-body DefId fingerprints, nested block
comments + unterminated diagnostic, implicit return for expression
bodies, interleaved contract fields with initializers, top-level
recovery resync, right-assoc arrow types, ternary expressions, precise
list/pred spans, TypeRef semantic/span separation.
Nameres (lens 2): public-name-keyed ambiguity/duplicate-export
validation per the reference (namespace kept in diagnostic identity),
call callees prefer functions over fields, declaration-span duplicate
export diagnostics that backdate.
Diagnostics (lens 4): DiagnosticId hashes level+suggestions, stable
sort tie-breaker, content check before absolute resolution in render.

Each finding carries a regression test (675 -> 692 tests).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The main tracked queries carry #[tracing::instrument] spans with
compact identifiers, fixpoint iteration / module loading / parser
recovery / import resolution emit debug events, and the salsa 0.27
event callback is bridged to a dedicated 'salsa' tracing target so
incremental behavior (WillExecute vs validation) is observable via
RUST_LOG. The driver gains --trace and EnvFilter wiring; hot paths
stay at trace level with zero cost when disabled.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@Y-Nak

Y-Nak commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

closing this PR in favor of #2

@Y-Nak Y-Nak closed this Jul 7, 2026
@Y-Nak
Y-Nak deleted the name-resolution branch July 23, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant