Module: Rigor::Inference::DefNodeResolver
- Defined in:
- lib/rigor/inference/def_node_resolver.rb
Overview
ADR-85 WD3 — resolves a DefHandle (stored in a bundle-rebuilt discovery table) to a live
Prism::DefNode, through a per-run parse memo that yields ONE stable node object per (path, node_id)
per run. Identity stability is a correctness constraint, not an optimisation: the ADR-84 return memo keys
on the resolved def-node's object identity, so a fresh parse per resolution would mint a new identity
each time and fragment that memo. The memo parses each demanded file at most once (recon Q5: an
incremental recheck demands 0–6 files' bodies), builds a node_id → DefNode index over its DefNodes, and
returns the same object on every later lookup.
node_id is the primary key; name is a cross-check. A miss (the node_id is absent, or its node's name
differs — a bundle/source skew the digest gate should make impossible, since identical bytes under the
same Prism yield identical node_ids) falls back to the first same-named DefNode in a fresh walk of the
file, and finally nil — conservative (the accessor then reports no user def, losing precision but never
firing a wrong diagnostic), never silent.
The memo is a thread-local installed for the duration of a run (the Cache::FileDigest pattern: process-local, Ractor-safe, never crosses a fork boundary, reset per run). Outside a run scope every resolution parses directly — a correct if un-memoised fallback for runner-less probes.
Class Method Summary collapse
-
.resolve(handle) ⇒ Object
Resolves
handleto aPrism::DefNode(the same object across the run for a given (path, node_id)), or nil. -
.with_run ⇒ Object
Installs a fresh per-run resolution memo, restoring the previous one on exit (always, even on a raise).
Class Method Details
.resolve(handle) ⇒ Object
Resolves handle to a Prism::DefNode (the same object across the run for a given (path, node_id)), or
nil. A non-handle argument is returned unchanged, so callers can pass a table value that is either a live
node (cold / re-walked file) or a handle (unchanged file) without branching.
43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/rigor/inference/def_node_resolver.rb', line 43 def self.resolve(handle) return handle unless handle.is_a?(DefHandle) memo = Thread.current[MEMO_KEY] return locate(handle, {}) if memo.nil? key = [handle.path, handle.node_id].freeze nodes = memo[:nodes] return nodes[key] if nodes.key?(key) nodes[key] = locate(handle, memo[:indexes]) end |
.with_run ⇒ Object
Installs a fresh per-run resolution memo, restoring the previous one on exit (always, even on a raise).
nodes caches the resolved node per (path, node_id); indexes caches each file's parse index.
32 33 34 35 36 37 38 |
# File 'lib/rigor/inference/def_node_resolver.rb', line 32 def self.with_run previous = Thread.current[MEMO_KEY] Thread.current[MEMO_KEY] = { nodes: {}, indexes: {} } yield ensure Thread.current[MEMO_KEY] = previous end |