Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 33 additions & 14 deletions dag/std/occurrence_binding_candidates.dag
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import std.occurrence_identity {
import std.decl_ref { DeclarationRef, WholeDeclaration }
import std.roster_frontier { declaration_ref_eq }
import std.occurrence_binding_resolve {
resolve_reference_occurrence_binding,
resolve_reference_occurrence_binding_validated,
OccurrenceReferenceBindingOutcome,
OccurrenceReferenceBindingDecided,
OccurrenceReferenceBindingTransportRefused,
Expand Down Expand Up @@ -691,12 +691,32 @@ fn declaration_exposed_on_reference_chain(
// declarations_by_name buckets every declaration by its authored spelling so a single reference's
// candidate lookup is a map_get plus a scan of only the same-spelled declarations, never a rescan
// of the whole declaration population -- the O(declarations x references) shape the pre-strip
// candidate scan had. entries_by_id is the same validated lookup authority
// std.occurrence_binding_resolve builds internally; it is retained here only to read authored_name,
// never to re-decide cardinality.
// candidate scan had.
//
// THE INDEX CARRIES THE VALIDATED TRANSPORT, NOT A COPY OF ONE OF ITS FIELDS, AND THAT IS A COST
// REPAIR RATHER THAN A REFACTOR. This type previously held `entries_by_id`, described as "the same
// validated lookup authority std.occurrence_binding_resolve builds internally". It was the same
// map -- and holding only that one field is what forced the resolver to REBUILD the other four:
// resolve_reference_via_structural_candidates could not hand a ValidatedOccurrenceTransport down,
// so it called std.occurrence_binding_resolve resolve_reference_occurrence_binding, whose first
// act is occurrence_transport_validate over the WHOLE transport -- three full folds across every
// index entry, declaration and reference, PER REFERENCE RESOLVED.
//
// So the "built exactly once" contract this comment opens with was true of the index and false of
// the path: validation was O(references x population), and the once-built index was defeated one
// layer below itself. MEASURED, not reasoned: the census instrument
// (src/v1/stage0/src/bin/type_occurrence_binding_census.rs) resolving dag/std -- 142 files -- ran
// past a 45-minute wall producing nothing.
//
// occurrence_candidate_index_build ALREADY validates exactly once and already had the whole
// ValidatedOccurrenceTransport in hand; it discarded four fifths of it. Retaining it is strictly
// FEWER representations of one fact, not more: entries_by_id is reached as
// `index.validated.entries_by_id`, there is no second copy to drift, and the cardinality decision
// still happens exactly once downstream. This is DESIGN section 6's bare-minimum-cost standing
// rule, whose n here is every type occurrence in the corpus.

type OccurrenceCandidateIndex {
entries_by_id: Map<Int, OccurrenceIndexEntry>
validated: ValidatedOccurrenceTransport
declarations_by_name: Map<String, List<DeclarationOccurrence>>
module_by_occurrence: Map<Int, NonEmptyStr>
exposure_by_occurrence: Map<Int, DeclarationExposure>
Expand Down Expand Up @@ -839,7 +859,7 @@ fn occurrence_candidate_index_build(
DeclarationsByNameReady { by_name: by_name } =>
OccurrenceCandidateIndexReady {
index: OccurrenceCandidateIndex {
entries_by_id: validated.entries_by_id,
validated: validated,
declarations_by_name: by_name,
module_by_occurrence: module_path_build.module_by_occurrence,
exposure_by_occurrence: exposure_build.exposure_by_occurrence,
Expand Down Expand Up @@ -868,7 +888,7 @@ fn candidate_occurrence_ids_for_reference(
index: OccurrenceCandidateIndex,
reference: ReferenceOccurrence
) -> List<OccurrenceId> {
match map_get(index.entries_by_id, reference.occurrence.value) {
match map_get(index.validated.entries_by_id, reference.occurrence.value) {
Absent => []
Present { value: entry } =>
match map_get(index.declarations_by_name, entry.projection.authored_name) {
Expand Down Expand Up @@ -1721,7 +1741,6 @@ fn structural_binding_walk_selected_references(
StructuralBindingWalkReady {
population: bound_reference_population_from_projections(
projections: resolve_all_references_via_structural_candidates(
transport: transport,
index: index,
references: references,
),
Expand Down Expand Up @@ -2518,17 +2537,20 @@ fn resolve_type_reference_containment_binding(
// are surfaced as their own typed, located outcomes so a caller can never mistake 'no edge' for
// 'one edge'.

// NO `transport` PARAMETER, DELIBERATELY. The index now carries the VALIDATED transport, and a
// second unvalidated OccurrenceTransport beside it would be two representations of one fact with
// nothing forcing them to be the same transport -- the caller could hand in a different one and
// the mismatch would resolve silently against whichever the arm happened to read.
fn resolve_reference_via_structural_candidates(
transport: OccurrenceTransport,
index: OccurrenceCandidateIndex,
reference: ReferenceOccurrence
) -> ReferenceBindingProjection {
let candidates = candidate_occurrence_ids_for_reference(
index: index,
reference: reference,
)
match resolve_reference_occurrence_binding(
transport: transport,
match resolve_reference_occurrence_binding_validated(
validated: index.validated,
occurrence: reference.occurrence,
supplied_candidates: candidates,
) {
Expand Down Expand Up @@ -2592,20 +2614,17 @@ fn resolve_reference_binding_via_structural_candidates(
ReferenceBindingProjectionDeclarationBucketRefused { occurrence: occurrence }
OccurrenceCandidateIndexReady { index: index } =>
resolve_reference_via_structural_candidates(
transport: transport,
index: index,
reference: reference,
)
}
}

fn resolve_all_references_via_structural_candidates(
transport: OccurrenceTransport,
index: OccurrenceCandidateIndex,
references: List<ReferenceOccurrence>
) -> List<ReferenceBindingProjection> {
references |> map(reference => resolve_reference_via_structural_candidates(
transport: transport,
index: index,
reference: reference,
))
Expand Down
12 changes: 9 additions & 3 deletions dag/std/reference_binding_observation.dag
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import std.occurrence_binding_candidates {
}
import std.occurrence_binding_resolve {
OccurrenceReferenceBindingOutcome,
resolve_reference_occurrence_binding,
resolve_reference_occurrence_binding_validated,
}
import std.types { Bool, FilePath, Int, List, String }

Expand Down Expand Up @@ -118,6 +118,12 @@ type ReferenceBindingObservation
projected_dependencies: List<FilePath>,
}

// THE SECOND SITE OF THE VALIDATED-TRANSPORT REPAIR, carried here rather than left for later
// because one fact with two homes is exactly what lets a repaired path sit beside an unrepaired
// one answering the same question -- and the next author picks whichever they read first.
// occurrence_candidate_index_build has ALREADY validated this transport, so calling the
// unvalidated std.occurrence_binding_resolve entry point would re-fold the whole population for
// THIS ONE reference: the O(references x population) shape measured on the resolve path.
fn structural_binding_resolution_from_candidates(
transport: OccurrenceTransport,
inputs: OccurrenceBindingCandidateInputs,
Expand All @@ -126,8 +132,8 @@ fn structural_binding_resolution_from_candidates(
match occurrence_candidate_index_build(transport: transport, inputs: inputs) {
OccurrenceCandidateIndexReady { index: index } =>
StructuralBindingResolved {
binding_outcome: resolve_reference_occurrence_binding(
transport: transport,
binding_outcome: resolve_reference_occurrence_binding_validated(
validated: index.validated,
occurrence: reference.occurrence,
supplied_candidates: candidate_occurrence_ids_for_reference(
index: index,
Expand Down
10 changes: 10 additions & 0 deletions src/v1/stage0/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ path = "src/bin/claim_executor.rs"
name = "carrier_realization_census"
path = "src/bin/carrier_realization_census.rs"

# XL-0T-CUTOVER census: over the complete production TypeOccurrence population, what the
# module-wide bare-name TypeEnv path (X, as repaired by #9813) binds versus what the exact
# per-occurrence containment authority (Y,
# std.occurrence_binding_candidates.resolve_type_reference_containment_binding) binds. The
# denominator is the corpus, so it is an instrument rather than a test, and it is named here
# so no number it reports is ever transcribed as an authority (DESIGN section 6).
[[bin]]
name = "type_occurrence_binding_census"
path = "src/bin/type_occurrence_binding_census.rs"

# Whole-tree `.dag` source read discovery for Stage C Lane 3a SourceRootIngest.
[[bin]]
name = "discover_source_root_ingest"
Expand Down
Loading
Loading