One heads reading per file: pool census projects it instead of re-parsing (resolver cost, step 2) - #12656
Conversation
The via-index parse and the parse-cache miss arm re-lexed every closure file the pool census had already lexed under the same spelling. Both now ask pool_acquire. Adds the per-term attribution probe and a live identity differential (pooled vs fresh artifact over the whole pool). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…-parsing pool_acquire holds one file-local heads reading (empty intern table, occurrence ordinals from zero). module_path_index reads it as-is; the pool census maps it into its threaded intern/occurrence space by a total projection (occurrence ids offset by the entry base, idents relabeled through the file's string list) instead of parsing the file a second time. Anything the parser does not produce refuses. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Every Node field and every ExprData / MatchPattern / InferredNode arm is named with no '..' or wildcard, so a field or variant added later fails to compile at the walker instead of passing through with file-local ids (review 72735). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Addressing review 72735. Catch-all arms: fixed in c927086. Seed receipt (advisory): no before/after seed census was run. That is a gap, and I'm naming it. The admission is the v2 program ( — sent from bold-bat-516 |
…heads # Conflicts: # src/v1/stage0/src/cli_run/entry_resolve.rs
…ites it, so Some refuses Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Merged main in (no force-push) and retargeted this PR onto main after #12643 landed. Main's #12612 added — sent from bold-bat-516 |
Step 2 of the resolver-cost item (node adhoc-a1f0bab0-a69, under jolly-boar-500). Stacked on #12643, which adds the attribution probe; the base changes to
mainonce #12643 lands. The shape follows jolly-boar-500's decision (option A): one heads reading per file, projected rather than parsed again.Defect
Every pool file was heads-parsed twice in one process:
module_path_index::parse_module_binding, in a fresh per-file space, to index module paths;parse_module_heads_for_pool_census), threading one intern table and occurrence space across the pool.The two reads parse the same bytes with the same grammar reading. They differ only in which intern/occurrence space the results are numbered in.
Change
pool_acquire::heads_reading_for: one heads reading per (spelling, bytes), parsed in a file-local space (empty intern table, occurrence ordinals from 0). It is a pure function of its key, so two consumers can share it.parse_module_bindingreads it as-is. It only uses the module name, its span and the refusal, and none of those carry an id.census_heads::project_heads_readinginto its threaded space instead of parsing again. The projection is total:kbecomesbase + k, and the allocator leaves atbase + local_next;relabel[k]is the pool id.InferredNode::Resolved, which the parser uses for written type expressions.Controls
entry_resolve::heads_projection_live_differential::projected_heads_equal_the_threaded_parse_on_the_live_pool. It feeds every file of the[dag, src/v2]shared index, inpool_parseorder, through both the old threaded parse and the new projection. It compares:Node(every occurrence id and every ident);census_heads::heads_projection_tests::projected_heads_equal_the_threaded_parse_at_identity_graincovers strings repeated across files, a variant match and a malformed head.the_unprojected_local_reading_is_not_the_threaded_readingis the red the comparison exists to catch: without the projection, the local reading differs from the threaded one from the second file on.censusandheadsunit tests pass, and clippy-D warningsis clean.InferredNode::Resolvedfield types. That is the fail-closed arm working as designed; the projection now maps them.Per-term table
Measured by
entry_resolve::live_pool_entry_resolve_attribution(see #12643 for the runner setup), one cold process per column. Totals are not compared: two runs of the same tree differ by more than this change moves them.The remaining 4.2s is the projection itself (node rebuild plus interning into persistent maps), not a parse. It could be reduced further, but that would be a constant-factor change, not a cost-shape one.
Found while reading (next PR, not here)
tree_bare_census_for_rootrebuildsbuild_symbol_index_census_raw_nodesovertree_census_nodes(index, root). That is the same pure function on the same arguments thatclosure_name_census(index, Some(root))already built and memoized, so it's a second raw census per root. The typed-census PR will derive the tree census from that memo and then scope the signature upgrade to what the closure demands.Hand-Rust receipt (v1 seed)
gunbc.v1_maintenance_standingv1_seed_standing). It removes a duplicated whole-pool parse from every--entryresolve.cli_run::{pool_acquire, census_heads}andmodule_path_indexsurface, and dissolves with the census when it moves to.dag.Do not merge; landing goes through the operator.
🤖 Generated with Claude Code