pub fn build_driver_graph<'d>(
netlist: &Netlist<'d>,
slang_analysis: &Analysis<'d>,
) -> DriverGraphExpand description
Second load-bearing finding, TDD’d against real sv-lang output
(verified this task): sv_lang::Analysis (slang::analysis:: AnalysisManager) tracks driver/procedure data per CANONICAL instance
only — confirmed empirically against a fixture with two instances
(i0, i1) of one shared module: slang_analysis.procedures(i0_body) .count() == 3 (i0 happened to be canonical) while
slang_analysis.procedures(i1_body).count() == 0, even though Task 2’s
own DisableInstanceCaching finding already established i0’s and
i1’s own AST bodies are genuinely distinct Symbols (never pointer-
shared). This is AnalysisManager.h’s own documented behavior (“driver
state tracked PER CANONICAL INSTANCE”) — a SEPARATE, analysis-layer-only
canonicalization from DisableInstanceCaching‘s elaboration-layer
pointer-identity guarantee. Consequence: Analysis::drivers/
Analysis::procedures can only ever be queried against ONE
representative instance per deduped Template — never a genuinely
per-instance call — so this function computes the write/read STRUCTURAL
PATTERN (as (SymbolKey, SymbolKey) pairs) once per Template, against
its own canonical instance (found by [representative_instance_of],
which — unlike populate_driver_kinds’ “any instance is correct,
Decision 4 guarantees identical shape” reasoning — must specifically
locate the one instance Analysis actually populated data for, not
merely the lowest InstanceId), then FANS that pattern OUT onto every
instance sharing the Template, using each instance’s own InstanceId.
Clock-domain seeding stays genuinely per-instance regardless (NL-076: it
never calls Analysis at all — it reads Template.processes, already
derived directly from raw sv_lang in elaborate(), so i0’s and
i1’s own distinct InstantiatedSignalIds for their clk port already
differ correctly with no canonicalization pitfall).
Deviation from the plan’s literal “built by zipping
Analysis::drivers()/Analysis::driver_handles()” wording: this
implementation uses Analysis::drivers() (DriverInfo) alone —
DriverInfo already exposes both .kind() (DriverEntry.driver_kind)
and .containing_symbol() (the process-identity resolution this graph
needs); Analysis::driver_handles()’s ValueDriver adds
.source()/.is_unidirectional_port()/bit-range/override-range data no
test in this task’s plan section exercises, so it is not fetched. Adapts
minimally, keeps the specified edge set.