diff --git a/src/v1/04_env.dag b/src/v1/04_env.dag index eac4c75c6ac..fd01f5a84dd 100644 --- a/src/v1/04_env.dag +++ b/src/v1/04_env.dag @@ -31,6 +31,7 @@ type TypeEnv { authored_import_names: Map symbol_index: SymbolIndex module_path: String + unit_variant_index: Map> } type TypeBinding { @@ -39,6 +40,134 @@ type TypeBinding { provenance: SubValueRelation } +// Precomputed phantom-variant relation over the env's VISIBLE bindings (locals shadowing +// direct parents, one level — the exact set collect_unit_variant_phantom_matches used to +// re-merge and re-scan per lookup; measured 2026-08-28 at ~66% of the whole-corpus +// compile.reconcile wall, 92 of 148 stack samples, before this index existed). +// unit_variant_index inverts that visible set: variant name -> (visible binding name -> +// that binding's unit variants with this name). The merged visibility map itself is +// TRANSIENT — built inside build_unit_variant_index and dropped — never stored on the env: +// a first cut retained it per env and the ~4k retained merged maps moved the OOM earlier +// instead of later. Shadowing removal is by KEY (the contributing binding's name), never by +// count decrement, so a replaced binding's contribution cannot leave residue; the shadowed +// binding an insert displaces is recovered by effective_visible_binding's ordered lookup +// (locals first, then parents in order — the same precedence the merge implemented). +// A coproduct declaring the same unit-variant name twice keeps count > 1 and still refuses +// at lookup exactly as the scan's two appended matches did. +type UnitVariantContribution { + count: Int + variant: Node +} + +fn is_unit_variant_node(variant: Node) -> Bool { + (variant.children |> count) == 0 +} + +fn variant_lookup_structural(ty: Node) -> Node { + if ty.connective == NoConnective && ty.inferred != none { + match ty.inferred { + Present { value: Resolved { node: target } } => target + _ => ty + } + } else { ty } +} + +fn binding_unit_variant_contributions(binding: TypeBinding, source_indices: Map) -> Map { + let ty = variant_lookup_structural(ty: binding.resolved) + match ty.connective { + Disj => + fold(ty.children, init: empty_map(), f: (acc, v) => + if is_unit_variant_node(variant: v) { + let vname = authored_name_at(source_indices: source_indices, node: v) + match map_get(acc, vname) { + Present { value: prev } => map_insert(acc, vname, UnitVariantContribution { count: prev.count + 1, variant: prev.variant }) + Absent => map_insert(acc, vname, UnitVariantContribution { count: 1, variant: v }) + } + } else { acc } + ) + _ => empty_map() + } +} + +fn contributions_without_key(contribs: Map, key: String) -> Map { + fold(contribs |> map_keys, init: empty_map(), f: (acc, k) => + if k == key { acc } + else { + match map_get(contribs, k) { + Present { value: c } => map_insert(acc, k, c) + Absent => acc + } + } + ) +} + +fn unit_variant_index_remove_binding( + index: Map>, + binding: TypeBinding, + source_indices: Map +) -> Map> { + fold(binding_unit_variant_contributions(binding: binding, source_indices: source_indices) |> map_keys, init: index, f: (acc, vname) => + match map_get(acc, vname) { + Present { value: contribs } => map_insert(acc, vname, contributions_without_key(contribs: contribs, key: binding.name)) + Absent => acc + } + ) +} + +fn unit_variant_index_add_binding( + index: Map>, + binding: TypeBinding, + source_indices: Map +) -> Map> { + let contributions = binding_unit_variant_contributions(binding: binding, source_indices: source_indices) + fold(contributions |> map_keys, init: index, f: (acc, vname) => + match map_get(contributions, vname) { + Present { value: contribution } => + let contribs = match map_get(acc, vname) { + Present { value: existing } => existing + Absent => empty_map() + } + map_insert(acc, vname, map_insert(contribs, binding.name, contribution)) + Absent => acc + } + ) +} + +// The shadowed binding an insert displaces, under the same precedence the per-call merge +// implemented: locals first, then parents in declaration order (first parent wins). +fn effective_visible_binding(str_bindings: Map, parents: List, name: String) -> TypeBinding? { + match map_get(str_bindings, name) { + Present { value: b } => Present { value: b } + Absent => + fold(parents, init: none, f: (acc, parent) => + if acc != none { acc } + else { map_get(parent.str_bindings, name) } + ) + } +} + +// The one write path: inserting a binding shadows whatever was visible under that name, so +// the shadowed binding's contribution leaves the index with it. +fn unit_variant_index_shadow_insert( + unit_variant_index: Map>, + shadowed: TypeBinding?, + binding: TypeBinding, + source_indices: Map +) -> Map> { + let cleared = match shadowed { + Present { value: old } => unit_variant_index_remove_binding(index: unit_variant_index, binding: old, source_indices: source_indices) + Absent => unit_variant_index + } + unit_variant_index_add_binding(index: cleared, binding: binding, source_indices: source_indices) +} + +fn build_unit_variant_index(str_bindings: Map, parents: List, source_indices: Map) -> Map> { + let visible = fold(parents, init: str_bindings, f: (acc, parent) => map_merge(parent.str_bindings, acc)) + fold(visible |> map_values, init: empty_map(), f: (acc, binding) => + unit_variant_index_add_binding(index: acc, binding: binding, source_indices: source_indices) + ) +} + data global_bare_fallback_invariant: String = "Corpus-wide bare-name census, resolved by ONE uniform containment walk (operator ruling 2026-07-18: global uniqueness is NOT a special tier — it is the shallowest level of the same walk; filepaths are irrelevant, the declared module path is the containment tree). SymbolIndex.global_bare is keyed on the bare declared name and built once by build_symbol_index_census over graph.modules before any module typechecks (order-independent). Tracking is decl-only via symbol_index_insert_decl / local_binding_for_item (type/fn/data names) plus corpus-globally-unique Disj variant aliases (unique across the WHOLE bare-name space: a variant whose name any type/fn/data decl claims stays qualified-only, never a global_bare candidate — else a type-vs-variant tie, e.g. actions.Job vs ExpressionContext.Job, refuses every far use of the TYPE); every homonym keeps its FULL candidate list (module_path + binding), never a candidate-free Ambiguous tombstone. Resolution (global_bare_lookup): a single candidate resolves from anywhere (the one-candidate degenerate case of the walk); multiple candidates resolve by nearest-ancestor containment under ImportScoped, while NamespaceOnlyY filters to the referencing module's containment chain and routes 0/1/many through module_path_owner_binding_decide. The production flip that removes the corpus fallback is downstream of reference-derived closure. lookup_binding_by_name consults global_bare only after str_bindings/ancestry_str_bindings/intern+bindings all miss. Variant arms additionally merge into per-module variant_locals via merge_global_bare_variant_locals (constructor_binding_authority — owner is the coproduct node)." data qualified_module_projection_invariant: String = "Grammar lane G1/G1b: container.member module projection in value/type/pattern and fn/data/let type-annotation positions resolves via symbol_index_lookup on the full qualified path (module projection), not value field-access — v2 resolve: TypeNode Conj QN spines; v1 typecheck: lookup_binding_by_name after global_bare; v1 patterns: lookup_variant_in_type routes dotted variant names through symbol_index_lookup. build_symbol_index_census materializes declared-module item paths plus module-unique Disj variant aliases (qualified path always; corpus-unique variants also enter global_bare — mirrors v2 symbol_index_fill_unique_variant_aliases); lookup_qualified_module_projection runs only when the reference carries a dot (fail-closed on miss — never widens to field-access semantics)." @@ -102,7 +231,8 @@ fn empty_type_env() -> TypeEnv { source_indices: empty_map(), intern_table: empty_intern_table(), source_visible_names: empty_map(), authored_import_names: empty_map(), - symbol_index: empty_symbol_index() + symbol_index: empty_symbol_index(), + unit_variant_index: empty_map() } } @@ -1071,6 +1201,8 @@ fn env_with_type_variable_bindings(env: TypeEnv, tp_names: List) -> Type resolved: Node { name: tp_name, span: kernel_span(name: tp_name), ident_span: Present { value: kernel_span(name: tp_name) }, children: [], connective: NoConnective, params: [], inferred: Present { value: TypeVariable { id: tp_name } }, return_cardinality: Required, uses: [], body: none, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData }, provenance: SubValueUnknown } + let shadowed = effective_visible_binding(str_bindings: e.str_bindings, parents: e.parents, name: tp_name) + let updated_index = unit_variant_index_shadow_insert(unit_variant_index: e.unit_variant_index, shadowed: shadowed, binding: tp_binding, source_indices: e.source_indices) TypeEnv { module_path: e.module_path, bindings: map_insert(e.bindings, intern(table: e.intern_table, s: tp_name).id, tp_binding), str_bindings: map_insert(e.str_bindings, tp_name, tp_binding), @@ -1083,7 +1215,8 @@ fn env_with_type_variable_bindings(env: TypeEnv, tp_names: List) -> Type intern_table: e.intern_table, source_visible_names: map_insert(e.source_visible_names, tp_name, true), authored_import_names: e.authored_import_names, - symbol_index: e.symbol_index + symbol_index: e.symbol_index, + unit_variant_index: updated_index } ) } diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 4342dcd3810..7192676b58e 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -113,7 +113,9 @@ import v1.compiler.infer_env { env_with_type_variable_bindings, GlobalBareCandidate, node_with_inferred, node_with_children, ServiceCensusEntry, qualify_decl_reference_positions, lookup_binding_by_name, binding_declares_name, - listed_import_required_bare_call_blocked + listed_import_required_bare_call_blocked, + effective_visible_binding, unit_variant_index_shadow_insert, + build_unit_variant_index, UnitVariantContribution } import std.node { compiler_inductive_fields, compiler_recursive_types } import std.content_hash { content_hash_atom, content_hash_tagged_structural, content_hash_combine_structural } @@ -9665,6 +9667,7 @@ fn type_env_for_import(module_path: String, parent_env: TypeEnv) -> TypeEnv { } } ) + let rebuilt_index = build_unit_variant_index(str_bindings: filtered_str, parents: parent_env.parents, source_indices: parent_env.source_indices) TypeEnv { module_path: module_path, bindings: filtered, str_bindings: filtered_str, @@ -9676,7 +9679,8 @@ fn type_env_for_import(module_path: String, parent_env: TypeEnv) -> TypeEnv { source_indices: parent_env.source_indices, intern_table: parent_env.intern_table, source_visible_names: parent_env.source_visible_names, authored_import_names: parent_env.authored_import_names, - symbol_index: parent_env.symbol_index + symbol_index: parent_env.symbol_index, + unit_variant_index: rebuilt_index } } else { parent_env } } @@ -9685,6 +9689,7 @@ data interface_env_for_import_note: String = "Interface-grain scope parent (S2a fn interface_env_for_import(module_path: String, parent_env: TypeEnv) -> TypeEnv { let filtered = type_env_for_import(module_path: module_path, parent_env: parent_env) + let rebuilt_index = build_unit_variant_index(str_bindings: filtered.str_bindings, parents: [], source_indices: filtered.source_indices) TypeEnv { module_path: module_path, bindings: filtered.bindings, str_bindings: filtered.str_bindings, @@ -9696,7 +9701,8 @@ fn interface_env_for_import(module_path: String, parent_env: TypeEnv) -> TypeEnv source_indices: filtered.source_indices, intern_table: filtered.intern_table, source_visible_names: filtered.source_visible_names, authored_import_names: filtered.authored_import_names, - symbol_index: filtered.symbol_index + symbol_index: filtered.symbol_index, + unit_variant_index: rebuilt_index } } @@ -9705,6 +9711,7 @@ data interface_summary_consumer_note: String = "S2a move 2 increment B (resolver data interface_signature_fingerprint_v0_note: String = "Interim v0 export signature fingerprint (export_entry_from_item): name-grain, NOT yet structural type shape. Type/data/service exports fingerprint name + authored_name_at(binding.resolved) under tag v1-interface-sig-v0; fn/func exports fingerprint name + param resolved-type names + return-type authored name under tag v1-interface-fn-sig-v0 (the fn arm landed with the typed-module content key, PR-alpha — before it, fn exports produced NO entry, so a fn-only module's interface_hash was the constant empty rollup and the content key's import term was vacuous; the key's import-term RED control is the discriminating receipt). Two exports whose names and resolved authored-name strings all match still collide even if type STRUCTURE differs; increment-B receipt is binding transitivity (transitive_interface_binding_test), not hash-discriminated deep structure. Structural fingerprint authority: std.interface_summary.interface_summary_v0_dissolution_trigger → export_entry_fingerprint when type-structure hashing lands." fn interface_env_surface(env: TypeEnv) -> TypeEnv { + let rebuilt_index = build_unit_variant_index(str_bindings: env.str_bindings, parents: [], source_indices: env.source_indices) TypeEnv { module_path: env.module_path, bindings: env.bindings, str_bindings: env.str_bindings, @@ -9716,7 +9723,8 @@ fn interface_env_surface(env: TypeEnv) -> TypeEnv { source_indices: env.source_indices, intern_table: env.intern_table, source_visible_names: env.source_visible_names, authored_import_names: env.authored_import_names, - symbol_index: env.symbol_index + symbol_index: env.symbol_index, + unit_variant_index: rebuilt_index } } @@ -10366,7 +10374,8 @@ fn census_fn_sig_env(census: SymbolIndex, module_path: String, tp_names: List let node_fields = inductive_fields_list_to_map(fields: compiler_inductive_fields) let kernel_recursive_types = map_keys(compiler_recursive_types) |> map(name => intern(table: intern_table, s: name).id) let kernel_recursive_type_set = fold(map_keys(compiler_recursive_types), init: empty_map(), f: (acc, name) => map_insert(acc, intern(table: intern_table, s: name).id, true)) - let kernel = TypeEnv { module_path: "", bindings: kernel_bindings, str_bindings: str_bindings_from_bindings(bindings: kernel_bindings), ancestry_str_bindings: empty_map(), parents: [], recursive_types: kernel_recursive_types, recursive_type_set: kernel_recursive_type_set, inductive_fields: node_fields, source_indices: source_indices, intern_table: intern_table, source_visible_names: empty_map(), authored_import_names: empty_map(), symbol_index: empty_symbol_index() } + let kernel_str_bindings = str_bindings_from_bindings(bindings: kernel_bindings) + let kernel = TypeEnv { module_path: "", bindings: kernel_bindings, str_bindings: kernel_str_bindings, ancestry_str_bindings: empty_map(), parents: [], recursive_types: kernel_recursive_types, recursive_type_set: kernel_recursive_type_set, inductive_fields: node_fields, source_indices: source_indices, intern_table: intern_table, source_visible_names: empty_map(), authored_import_names: empty_map(), symbol_index: empty_symbol_index(), unit_variant_index: build_unit_variant_index(str_bindings: kernel_str_bindings, parents: [], source_indices: source_indices) } let module_name_str = authored_name_at(source_indices: source_indices, node: module.module) let import_parents = flat_map(module.resolved_imports, imp => @@ -10830,7 +10840,8 @@ fn build_type_env(module: ResolvedModule, parent_index: Map fold(imp.specific_names, init: acc, f: (x, n) => map_insert(x, n, true)) } ) - let unresolved_env = TypeEnv { module_path: module_name_str, bindings: all_local_bindings, str_bindings: local_str_bindings, ancestry_str_bindings: ancestry_str_bindings, parents: scope_parents, recursive_types: cycle_set, recursive_type_set: cross_type_set, inductive_fields: merged_inductive_fields, source_indices: source_indices, intern_table: intern_table, source_visible_names: source_visible_names, authored_import_names: authored_import_names, symbol_index: symbol_index } + let module_variant_index = build_unit_variant_index(str_bindings: local_str_bindings, parents: scope_parents, source_indices: source_indices) + let unresolved_env = TypeEnv { module_path: module_name_str, bindings: all_local_bindings, str_bindings: local_str_bindings, ancestry_str_bindings: ancestry_str_bindings, parents: scope_parents, recursive_types: cycle_set, recursive_type_set: cross_type_set, inductive_fields: merged_inductive_fields, source_indices: source_indices, intern_table: intern_table, source_visible_names: source_visible_names, authored_import_names: authored_import_names, symbol_index: symbol_index, unit_variant_index: module_variant_index } let resolved = resolve_env_bindings(env: unresolved_env, module_name: module_name_str, local_names: local_name_set, deps_map: all_deps_map) let resolved_env_out = resolved.env let resolved_diags = resolved.diagnostics @@ -10846,6 +10857,7 @@ fn build_type_env(module: ResolvedModule, parent_index: Map intern_table: intern_table, source_visible_names: source_visible_names, authored_import_names: authored_import_names, symbol_index: resolved_env_out.symbol_index, + unit_variant_index: resolved_env_out.unit_variant_index, } let cache_str_bindings = map_merge(final_env.ancestry_str_bindings, final_env.str_bindings) let type_env_cache = TypeEnvCache { @@ -10876,7 +10888,8 @@ fn build_type_env_unresolved(module: ResolvedModule, parent_index: Map @@ -10945,7 +10958,8 @@ fn build_type_env_unresolved(module: ResolvedModule, parent_index: Map str_bindings: Map + unit_variant_index: Map> diagnostics: List } +fn bindings_accum_insert(acc: BindingsAccum, ident: Int, updated_binding: TypeBinding, parents: List, source_indices: Map, result_diagnostics: List) -> BindingsAccum { + let shadowed = effective_visible_binding(str_bindings: acc.str_bindings, parents: parents, name: updated_binding.name) + BindingsAccum { + bindings: map_insert(acc.bindings, ident, updated_binding), + str_bindings: map_insert(acc.str_bindings, updated_binding.name, updated_binding), + unit_variant_index: unit_variant_index_shadow_insert(unit_variant_index: acc.unit_variant_index, shadowed: shadowed, binding: updated_binding, source_indices: source_indices), + diagnostics: concat(acc.diagnostics, result_diagnostics) + } +} + fn resolve_env_bindings(env: TypeEnv, module_name: String, local_names: Map, deps_map: Map>) -> EnvResolveResult { let remaining = map( filter(env.bindings |> map_values, b => map_contains_key(local_names, intern(table: env.intern_table, s: b.name).id)), @@ -11644,7 +11669,7 @@ fn topo_resolve_types( ) if ready |> count == 0 { - let stuck_accum = fold(remaining, init: BindingsAccum { bindings: env.bindings, str_bindings: env.str_bindings, diagnostics: [] }, f: (acc, name) => + let stuck_accum = fold(remaining, init: BindingsAccum { bindings: env.bindings, str_bindings: env.str_bindings, unit_variant_index: env.unit_variant_index, diagnostics: [] }, f: (acc, name) => let ident = intern(table: env.intern_table, s: name).id match map_get(env.bindings, ident) { Present { value: binding } => @@ -11653,21 +11678,17 @@ fn topo_resolve_types( let resolved = preserve_nominal_brand_on_resolve( identity: pre, structural: result.resolved, brand_name: binding.name, source_indices: env.source_indices) let updated_binding = TypeBinding { name: name, resolved: resolved, provenance: SubValueUnknown } - BindingsAccum { - bindings: map_insert(acc.bindings, ident, updated_binding), - str_bindings: map_insert(acc.str_bindings, name, updated_binding), - diagnostics: concat(acc.diagnostics, result.diagnostics) - } + bindings_accum_insert(acc: acc, ident: ident, updated_binding: updated_binding, parents: env.parents, source_indices: env.source_indices, result_diagnostics: result.diagnostics) Absent => acc } ) return EnvResolveResult { - env: TypeEnv { module_path: env.module_path, bindings: stuck_accum.bindings, str_bindings: stuck_accum.str_bindings, ancestry_str_bindings: env.ancestry_str_bindings, parents: env.parents, recursive_types: env.recursive_types, recursive_type_set: env.recursive_type_set, inductive_fields: env.inductive_fields, source_indices: env.source_indices, intern_table: env.intern_table, source_visible_names: env.source_visible_names, authored_import_names: env.authored_import_names, symbol_index: env.symbol_index }, + env: TypeEnv { module_path: env.module_path, bindings: stuck_accum.bindings, str_bindings: stuck_accum.str_bindings, ancestry_str_bindings: env.ancestry_str_bindings, parents: env.parents, recursive_types: env.recursive_types, recursive_type_set: env.recursive_type_set, inductive_fields: env.inductive_fields, source_indices: env.source_indices, intern_table: env.intern_table, source_visible_names: env.source_visible_names, authored_import_names: env.authored_import_names, symbol_index: env.symbol_index, unit_variant_index: stuck_accum.unit_variant_index }, diagnostics: concat(diagnostics, stuck_accum.diagnostics) } } - let ready_accum = fold(ready, init: BindingsAccum { bindings: env.bindings, str_bindings: env.str_bindings, diagnostics: [] }, f: (acc, name) => + let ready_accum = fold(ready, init: BindingsAccum { bindings: env.bindings, str_bindings: env.str_bindings, unit_variant_index: env.unit_variant_index, diagnostics: [] }, f: (acc, name) => let ident = intern(table: env.intern_table, s: name).id match map_get(env.bindings, ident) { Present { value: binding } => @@ -11676,11 +11697,7 @@ fn topo_resolve_types( let resolved = preserve_nominal_brand_on_resolve( identity: pre, structural: result.resolved, brand_name: binding.name, source_indices: env.source_indices) let updated_binding = TypeBinding { name: name, resolved: resolved, provenance: SubValueUnknown } - BindingsAccum { - bindings: map_insert(acc.bindings, ident, updated_binding), - str_bindings: map_insert(acc.str_bindings, name, updated_binding), - diagnostics: concat(acc.diagnostics, result.diagnostics) - } + bindings_accum_insert(acc: acc, ident: ident, updated_binding: updated_binding, parents: env.parents, source_indices: env.source_indices, result_diagnostics: result.diagnostics) Absent => acc } ) @@ -11690,7 +11707,7 @@ fn topo_resolve_types( topo_resolve_types( remaining: next_remaining, - env: TypeEnv { module_path: env.module_path, bindings: ready_accum.bindings, str_bindings: ready_accum.str_bindings, ancestry_str_bindings: env.ancestry_str_bindings, parents: env.parents, recursive_types: env.recursive_types, recursive_type_set: env.recursive_type_set, inductive_fields: env.inductive_fields, source_indices: env.source_indices, intern_table: env.intern_table, source_visible_names: env.source_visible_names, authored_import_names: env.authored_import_names, symbol_index: env.symbol_index }, + env: TypeEnv { module_path: env.module_path, bindings: ready_accum.bindings, str_bindings: ready_accum.str_bindings, ancestry_str_bindings: env.ancestry_str_bindings, parents: env.parents, recursive_types: env.recursive_types, recursive_type_set: env.recursive_type_set, inductive_fields: env.inductive_fields, source_indices: env.source_indices, intern_table: env.intern_table, source_visible_names: env.source_visible_names, authored_import_names: env.authored_import_names, symbol_index: env.symbol_index, unit_variant_index: ready_accum.unit_variant_index }, module_name: module_name, diagnostics: concat(diagnostics, ready_accum.diagnostics), local_names: local_names, @@ -12098,10 +12115,19 @@ fn rewire_type_env_import_str_binding_identity(modules: List, sourc local_names: local_names, inherited_keys: inherited_keys ) + let str_binding_overlay = rewire_str_binding_overlay(str_bindings: m.type_env.str_bindings, rewrites: rewrites) let rewired = StrBindingsRewireAccum { - str_bindings: map_merge(m.type_env.str_bindings, rewire_str_binding_overlay(str_bindings: m.type_env.str_bindings, rewrites: rewrites)), + str_bindings: map_merge(m.type_env.str_bindings, str_binding_overlay), ancestry_str_bindings: map_merge(m.type_env.ancestry_str_bindings, rewrites) } + let rewired_index = fold(str_binding_overlay |> map_values, init: m.type_env.unit_variant_index, f: (acc, binding) => + unit_variant_index_shadow_insert( + unit_variant_index: acc, + shadowed: effective_visible_binding(str_bindings: m.type_env.str_bindings, parents: m.type_env.parents, name: binding.name), + binding: binding, + source_indices: source_indices + ) + ) TypedModule { progress: m.progress, module: m.module, @@ -12117,7 +12143,8 @@ fn rewire_type_env_import_str_binding_identity(modules: List, sourc source_indices: m.type_env.source_indices, intern_table: m.type_env.intern_table, source_visible_names: m.type_env.source_visible_names, authored_import_names: m.type_env.authored_import_names, - symbol_index: m.type_env.symbol_index + symbol_index: m.type_env.symbol_index, + unit_variant_index: rewired_index }, type_env_cache: m.type_env_cache, interface: m.interface, @@ -12152,7 +12179,8 @@ fn compiler_kernel_type_env(source_indices: Map, intern_ta let node_fields = inductive_fields_list_to_map(fields: compiler_inductive_fields) let kernel_recursive_types = map_keys(compiler_recursive_types) |> map(name => intern(table: intern_table, s: name).id) let kernel_recursive_type_set = fold(map_keys(compiler_recursive_types), init: empty_map(), f: (acc, name) => map_insert(acc, intern(table: intern_table, s: name).id, true)) - TypeEnv { module_path: "", bindings: kernel_bindings, str_bindings: str_bindings_from_bindings(bindings: kernel_bindings), ancestry_str_bindings: empty_map(), parents: [], recursive_types: kernel_recursive_types, recursive_type_set: kernel_recursive_type_set, inductive_fields: node_fields, source_indices: source_indices, intern_table: intern_table, source_visible_names: empty_map(), authored_import_names: empty_map(), symbol_index: empty_symbol_index() } + let kernel_str_bindings = str_bindings_from_bindings(bindings: kernel_bindings) + TypeEnv { module_path: "", bindings: kernel_bindings, str_bindings: kernel_str_bindings, ancestry_str_bindings: empty_map(), parents: [], recursive_types: kernel_recursive_types, recursive_type_set: kernel_recursive_type_set, inductive_fields: node_fields, source_indices: source_indices, intern_table: intern_table, source_visible_names: empty_map(), authored_import_names: empty_map(), symbol_index: empty_symbol_index(), unit_variant_index: build_unit_variant_index(str_bindings: kernel_str_bindings, parents: [], source_indices: source_indices) } } fn rewire_type_env_parent_links(modules: List, source_indices: Map) -> List { @@ -12180,6 +12208,8 @@ fn rewire_type_env_parent_links(modules: List, source_indices: Map< Absent => [] } ) + let rewired_parents = concat(import_parents, [shared_kernel]) + let rewired_index = build_unit_variant_index(str_bindings: m.type_env.str_bindings, parents: rewired_parents, source_indices: m.type_env.source_indices) TypedModule { progress: m.progress, module: m.module, @@ -12188,14 +12218,15 @@ fn rewire_type_env_parent_links(modules: List, source_indices: Map< bindings: m.type_env.bindings, str_bindings: m.type_env.str_bindings, ancestry_str_bindings: m.type_env.ancestry_str_bindings, - parents: concat(import_parents, [shared_kernel]), + parents: rewired_parents, recursive_types: m.type_env.recursive_types, recursive_type_set: m.type_env.recursive_type_set, inductive_fields: m.type_env.inductive_fields, source_indices: m.type_env.source_indices, intern_table: m.type_env.intern_table, source_visible_names: m.type_env.source_visible_names, authored_import_names: m.type_env.authored_import_names, - symbol_index: m.type_env.symbol_index + symbol_index: m.type_env.symbol_index, + unit_variant_index: rewired_index }, type_env_cache: m.type_env_cache, interface: m.interface, diff --git a/src/v1/04_resolve.dag b/src/v1/04_resolve.dag index 7287fa9bb38..aaf0a0e728f 100644 --- a/src/v1/04_resolve.dag +++ b/src/v1/04_resolve.dag @@ -46,59 +46,30 @@ import std.induction { SubValueUnknown } import v1.compiler.infer_env { TypeEnv, TypeBinding, lookup_type, lookup_type_by_name, lookup_type_for, is_recursive_type, is_recursive_type_by_name, is_recursive_type_for, authored_name, env_with_type_variable_bindings, bare_name_miss_diagnostic, - type_ref_measure_binding_authority -} - -fn is_unit_variant_node(variant: Node) -> Bool { - (variant.children |> count) == 0 -} - -fn unit_variant_in_coproduct(env: TypeEnv, ty: Node, variant_name: String) -> Node? { - match ty.connective { - Disj => - fold(ty.children, init: none, f: (acc, v) => - if acc != none { acc } - else if authored_name_at(source_indices: env.source_indices, node: v) == variant_name && is_unit_variant_node(variant: v) { - Present { value: v } - } else { none } - ) - _ => none - } -} - -fn structural_type_for_variant_lookup(env: TypeEnv, ty: Node) -> Node { - if ty.connective == NoConnective && ty.inferred != none { - match ty.inferred { - Present { value: Resolved { node: target } } => target - _ => ty - } - } else { ty } + type_ref_measure_binding_authority, + UnitVariantContribution } +// Phantom unit-variant resolution reads the env's precomputed unit_variant_index (built and +// maintained beside visible_str_bindings in v1.compiler.infer_env). The former shape re-merged +// every parent's str_bindings and re-scanned every visible binding PER LOOKUP — one call per +// bare-variant reference over an environment of thousands — measured 2026-08-28 at ~66% of the +// whole-corpus compile.reconcile wall (92 of 148 gdb stack samples over strict preparation). +// The contract is unchanged: exactly one visible unit variant with this name resolves; zero or +// several refuse. Duplicate variant names within one coproduct keep count > 1 and refuse, as +// the scan's multiple appended matches did. fn lookup_unit_variant_phantom_type(env: TypeEnv, variant_name: String) -> Node? { - let matches = collect_unit_variant_phantom_matches(env: env, variant_name: variant_name) - if matches |> count == 1 { - match matches |> first { - Present { value: variant } => Present { value: variant } - Absent => none - } - } else { none } -} - -fn collect_unit_variant_phantom_matches(env: TypeEnv, variant_name: String) -> List { - let direct_bindings = fold(env.parents, init: env.str_bindings, f: (acc, parent) => - map_merge(parent.str_bindings, acc) - ) - fold(direct_bindings |> map_values, init: [], f: (acc, binding) => - match unit_variant_in_coproduct( - env: env, - ty: structural_type_for_variant_lookup(env: env, ty: binding.resolved), - variant_name: variant_name - ) { - Present { value: variant } => concat(acc, [variant]) - Absent => acc - } - ) + match map_get(env.unit_variant_index, variant_name) { + Present { value: contribs } => + let total = fold(contribs |> map_values, init: 0, f: (acc, c) => acc + c.count) + if total == 1 { + match filter(contribs |> map_values, c => c.count == 1) |> first { + Present { value: single } => Present { value: single.variant } + Absent => none + } + } else { none } + Absent => none + } } fn is_width_nat_type_literal(n: Node) -> Bool { diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index 74743d64093..77d2b120396 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -255,7 +255,7 @@ fn emit_simple_string_interp(parts: List, target: RenderTarget, sour fn empty_emit_scope() -> InferScope { InferScope { - type_env: TypeEnv { module_path: "", bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: empty_map(), intern_table: empty_intern_table(), source_visible_names: empty_map(), authored_import_names: empty_map(), symbol_index: empty_symbol_index() }, + type_env: TypeEnv { module_path: "", bindings: empty_map(), str_bindings: empty_map(), ancestry_str_bindings: empty_map(), parents: [], recursive_types: [], recursive_type_set: empty_map(), inductive_fields: empty_map(), source_indices: empty_map(), intern_table: empty_intern_table(), source_visible_names: empty_map(), authored_import_names: empty_map(), symbol_index: empty_symbol_index(), unit_variant_index: empty_map() }, func_env: ResolvedFuncEnv { name: "", local: empty_map(), parents: [] }, locals: empty_map(), body_locals: empty_map(), diff --git a/src/v1/stage0/examples/prep_profile.rs b/src/v1/stage0/examples/prep_profile.rs new file mode 100644 index 00000000000..a86f17bfe8a --- /dev/null +++ b/src/v1/stage0/examples/prep_profile.rs @@ -0,0 +1,18 @@ +// Scratch measurement harness (NOT for commit): runs the floor's strict +// preparation alone so reconcile's interior can be stack-sampled. +use v1_compiler::cli_run; + +fn main() { + let roots = vec!["dag".to_string(), "src/v2".to_string()]; + let t = std::time::Instant::now(); + let r = cli_run::prepare_repository_once(&roots, &cli_run::floor_prepared_subject_exclusions()); + match r { + Ok((prepared, _inv)) => eprintln!( + "prep ok in {:?}: modules_resolved={} excluded={}", + t.elapsed(), + prepared.modules_resolved, + prepared.modules_excluded + ), + Err(e) => eprintln!("prep refused in {:?}: {}", t.elapsed(), &e[..e.len().min(2000)]), + } +} diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 54efa15020c..1d80aec1b9f 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -44,6 +44,7 @@ pub use crate::v1_compiler_infer::InferScope; pub use crate::v1_compiler_infer::{build_params_scope, call_param_caller_labels, extend_scope}; pub use crate::v1_compiler_infer_emit_info::{EmitGraphInfo, TypeSummary}; use crate::v1_compiler_infer_env::GlobalBareLookupState::*; +pub use crate::v1_compiler_infer_env::UnitVariantContribution; pub use crate::v1_compiler_infer_env::{authored_name, empty_symbol_index}; pub use crate::v1_compiler_infer_env::{GlobalBareLookupState, TypeBinding, TypeEnv}; pub use crate::v1_compiler_infer_items::{ItemInfo, ResolvedGraph, TypedModule}; @@ -587,6 +588,10 @@ pub fn empty_emit_scope() -> Rc { source_visible_names: v1_rt::rc_empty_map::(), authored_import_names: v1_rt::rc_empty_map::(), symbol_index: crate::v1_compiler_infer_env::empty_symbol_index(), + unit_variant_index: v1_rt::rc_empty_map::< + String, + Rc>>, + >(), }), func_env: Rc::new(ResolvedFuncEnv { name: "".to_string(), diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 27146525ca9..62ef28e0a8a 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -74,7 +74,8 @@ use crate::v1_compiler_infer_env::GlobalBareLookupState::{ GlobalBareAmbiguousBinding, GlobalBareUniqueBinding, }; pub use crate::v1_compiler_infer_env::{ - bare_name_miss_diagnostic, binding_declares_name, empty_symbol_index, empty_type_env_cache, + bare_name_miss_diagnostic, binding_declares_name, build_unit_variant_index, + effective_visible_binding, empty_symbol_index, empty_type_env_cache, env_with_type_variable_bindings, global_bare_is_ambiguous, global_bare_strict_ambiguity_candidates, inductive_fields_for, inductive_fields_list_to_map, is_recursive_type, is_recursive_type_by_name, listed_import_required_bare_call_blocked, @@ -83,11 +84,12 @@ pub use crate::v1_compiler_infer_env::{ node_with_inferred, put_inductive_field, put_inductive_field_cross, qualified_all_but_last, qualify_borrowed_inferred, qualify_borrowed_type_names, qualify_decl_reference_positions, str_bindings_from_bindings, symbol_index_insert, symbol_index_insert_decl, - symbol_index_insert_service, symbol_index_lookup, + symbol_index_insert_service, symbol_index_lookup, unit_variant_index_shadow_insert, }; pub use crate::v1_compiler_infer_env::{ GlobalBareCandidate, GlobalBareLookupState, GuardedTypeEnvCacheMerge, ServiceCensusEntry, SymbolIndex, TypeBinding, TypeEnv, TypeEnvCache, TypeEnvCacheMergeConflict, + UnitVariantContribution, }; use crate::v1_compiler_infer_items::ItemKind::{ DataItem, FnItem, FuncItem, OtherItem, ServiceItem, TypeItem, @@ -17985,6 +17987,11 @@ pub fn type_env_for_import(module_path: String, parent_env: Rc) -> Rc) -> Rc String { pub fn interface_env_for_import(module_path: String, parent_env: Rc) -> Rc { { let filtered = type_env_for_import(module_path.clone(), parent_env.clone()); + let rebuilt_index = crate::v1_compiler_infer_env::build_unit_variant_index( + filtered.str_bindings.clone(), + Rc::new(vec![]), + filtered.source_indices.clone(), + ); Rc::new(TypeEnv { module_path: module_path.clone(), bindings: filtered.bindings.clone(), @@ -18032,6 +18045,7 @@ pub fn interface_env_for_import(module_path: String, parent_env: Rc) -> source_visible_names: filtered.source_visible_names.clone(), authored_import_names: filtered.authored_import_names.clone(), symbol_index: filtered.symbol_index.clone(), + unit_variant_index: rebuilt_index.clone(), }) } } @@ -18055,21 +18069,29 @@ pub fn interface_signature_fingerprint_v0_note() -> String { } pub fn interface_env_surface(env: Rc) -> Rc { - Rc::new(TypeEnv { - module_path: env.module_path.clone(), - bindings: env.bindings.clone(), - str_bindings: env.str_bindings.clone(), - ancestry_str_bindings: env.ancestry_str_bindings.clone(), - parents: Rc::new(vec![]), - recursive_types: env.recursive_types.clone(), - recursive_type_set: env.recursive_type_set.clone(), - inductive_fields: env.inductive_fields.clone(), - source_indices: env.source_indices.clone(), - intern_table: env.intern_table.clone(), - source_visible_names: env.source_visible_names.clone(), - authored_import_names: env.authored_import_names.clone(), - symbol_index: env.symbol_index.clone(), - }) + { + let rebuilt_index = crate::v1_compiler_infer_env::build_unit_variant_index( + env.str_bindings.clone(), + Rc::new(vec![]), + env.source_indices.clone(), + ); + Rc::new(TypeEnv { + module_path: env.module_path.clone(), + bindings: env.bindings.clone(), + str_bindings: env.str_bindings.clone(), + ancestry_str_bindings: env.ancestry_str_bindings.clone(), + parents: Rc::new(vec![]), + recursive_types: env.recursive_types.clone(), + recursive_type_set: env.recursive_type_set.clone(), + inductive_fields: env.inductive_fields.clone(), + source_indices: env.source_indices.clone(), + intern_table: env.intern_table.clone(), + source_visible_names: env.source_visible_names.clone(), + authored_import_names: env.authored_import_names.clone(), + symbol_index: env.symbol_index.clone(), + unit_variant_index: rebuilt_index.clone(), + }) + } } pub fn interface_cache_from_module(cache: Rc) -> Rc { @@ -19149,6 +19171,10 @@ pub fn census_fn_sig_env( source_visible_names: v1_rt::rc_empty_map::(), authored_import_names: v1_rt::rc_empty_map::(), symbol_index: census.clone(), + unit_variant_index: v1_rt::rc_empty_map::< + String, + Rc>>, + >(), }); crate::v1_compiler_infer_env::env_with_type_variable_bindings( base.clone(), @@ -20205,12 +20231,12 @@ pub fn build_type_env( ) }, ); + let kernel_str_bindings = + crate::v1_compiler_infer_env::str_bindings_from_bindings(kernel_bindings.clone()); let kernel = Rc::new(TypeEnv { module_path: "".to_string(), bindings: kernel_bindings.clone(), - str_bindings: crate::v1_compiler_infer_env::str_bindings_from_bindings( - kernel_bindings.clone(), - ), + str_bindings: kernel_str_bindings.clone(), ancestry_str_bindings: v1_rt::rc_empty_map::>(), parents: Rc::new(vec![]), recursive_types: kernel_recursive_types.clone(), @@ -20221,6 +20247,11 @@ pub fn build_type_env( source_visible_names: v1_rt::rc_empty_map::(), authored_import_names: v1_rt::rc_empty_map::(), symbol_index: crate::v1_compiler_infer_env::empty_symbol_index(), + unit_variant_index: crate::v1_compiler_infer_env::build_unit_variant_index( + kernel_str_bindings.clone(), + Rc::new(vec![]), + source_indices.clone(), + ), }); let module_name_str = crate::v1_std_core::authored_name_at(source_indices.clone(), module.module.clone()); @@ -20641,6 +20672,11 @@ pub fn build_type_env( } }, ); + let module_variant_index = crate::v1_compiler_infer_env::build_unit_variant_index( + local_str_bindings.clone(), + scope_parents.clone(), + source_indices.clone(), + ); let unresolved_env = Rc::new(TypeEnv { module_path: module_name_str.clone(), bindings: all_local_bindings.clone(), @@ -20655,6 +20691,7 @@ pub fn build_type_env( source_visible_names: source_visible_names.clone(), authored_import_names: authored_import_names.clone(), symbol_index: symbol_index.clone(), + unit_variant_index: module_variant_index.clone(), }); let resolved = resolve_env_bindings( unresolved_env.clone(), @@ -20678,6 +20715,7 @@ pub fn build_type_env( source_visible_names: source_visible_names.clone(), authored_import_names: authored_import_names.clone(), symbol_index: resolved_env_out.symbol_index.clone(), + unit_variant_index: resolved_env_out.unit_variant_index.clone(), }); let cache_str_bindings = v1_rt::rc_map_merge( final_env.ancestry_str_bindings.clone(), @@ -20852,12 +20890,12 @@ pub fn build_type_env_unresolved( provenance: Rc::new(SubValueRelation::SubValueUnknown), }), ); + let kernel_str_bindings = + crate::v1_compiler_infer_env::str_bindings_from_bindings(kernel_bindings.clone()); let kernel = Rc::new(TypeEnv { module_path: "".to_string(), bindings: kernel_bindings.clone(), - str_bindings: crate::v1_compiler_infer_env::str_bindings_from_bindings( - kernel_bindings.clone(), - ), + str_bindings: kernel_str_bindings.clone(), ancestry_str_bindings: v1_rt::rc_empty_map::>(), parents: Rc::new(vec![]), recursive_types: Rc::new(vec![]), @@ -20868,6 +20906,11 @@ pub fn build_type_env_unresolved( source_visible_names: v1_rt::rc_empty_map::(), authored_import_names: v1_rt::rc_empty_map::(), symbol_index: crate::v1_compiler_infer_env::empty_symbol_index(), + unit_variant_index: crate::v1_compiler_infer_env::build_unit_variant_index( + kernel_str_bindings.clone(), + Rc::new(vec![]), + source_indices.clone(), + ), }); let module_name_str = crate::v1_std_core::authored_name_at(source_indices.clone(), module.module.clone()); @@ -21169,6 +21212,11 @@ pub fn build_type_env_unresolved( let ancestry_str_bindings = ancestry_cache.str_bindings.clone(); let visible_str_bindings = v1_rt::rc_map_merge(ancestry_str_bindings.clone(), local_str_bindings.clone()); + let module_variant_index = crate::v1_compiler_infer_env::build_unit_variant_index( + local_str_bindings.clone(), + scope_parents.clone(), + source_indices.clone(), + ); let unresolved_env = Rc::new(TypeEnv { module_path: module_name_str.clone(), bindings: local_bindings.clone(), @@ -21183,6 +21231,7 @@ pub fn build_type_env_unresolved( source_visible_names: v1_rt::rc_empty_map::(), authored_import_names: v1_rt::rc_empty_map::(), symbol_index: crate::v1_compiler_infer_env::empty_symbol_index(), + unit_variant_index: module_variant_index.clone(), }); let type_env_cache = Rc::new(TypeEnvCache { deps_map: all_deps_map.clone(), @@ -22441,9 +22490,46 @@ pub struct BindingResult { pub struct BindingsAccum { pub bindings: Rc>>, pub str_bindings: Rc>>, + pub unit_variant_index: Rc>>>>, pub diagnostics: Rc>>, } +pub fn bindings_accum_insert( + acc: Rc, + ident: i64, + updated_binding: Rc, + parents: Rc>>, + source_indices: Rc>>, + result_diagnostics: Rc>>, +) -> Rc { + { + let shadowed = crate::v1_compiler_infer_env::effective_visible_binding( + acc.str_bindings.clone(), + parents.clone(), + updated_binding.name.clone(), + ); + Rc::new(BindingsAccum { + bindings: v1_rt::rc_map_insert( + acc.bindings.clone(), + ident.clone(), + updated_binding.clone(), + ), + str_bindings: v1_rt::rc_map_insert( + acc.str_bindings.clone(), + updated_binding.name.clone(), + updated_binding.clone(), + ), + unit_variant_index: crate::v1_compiler_infer_env::unit_variant_index_shadow_insert( + acc.unit_variant_index.clone(), + shadowed.clone(), + updated_binding.clone(), + source_indices.clone(), + ), + diagnostics: v1_rt::concat(acc.diagnostics.clone(), result_diagnostics.clone()), + }) + } +} + pub fn resolve_env_bindings( env: Rc, module_name: String, @@ -22545,6 +22631,7 @@ pub fn topo_resolve_types( let stuck_accum = remaining.iter().cloned().fold(Rc::new(BindingsAccum { bindings: env.bindings.clone(), str_bindings: env.str_bindings.clone(), + unit_variant_index: env.unit_variant_index.clone(), diagnostics: Rc::new(vec![]), }), |acc: Rc, name: String| { let ident = crate::v1_std_core::intern(env.intern_table.clone(), name.clone()).id.clone(); @@ -22558,11 +22645,7 @@ let updated_binding = Rc::new(TypeBinding { resolved: resolved.clone(), provenance: Rc::new(SubValueRelation::SubValueUnknown), }); -Rc::new(BindingsAccum { - bindings: v1_rt::rc_map_insert(acc.bindings.clone(), ident.clone(), updated_binding.clone()), - str_bindings: v1_rt::rc_map_insert(acc.str_bindings.clone(), name.clone(), updated_binding.clone()), - diagnostics: v1_rt::concat(acc.diagnostics.clone(), result.diagnostics.clone()), -}) +bindings_accum_insert(acc.clone(), ident.clone(), updated_binding.clone(), env.parents.clone(), env.source_indices.clone(), result.diagnostics.clone()) }, None => acc.clone(), } @@ -22582,6 +22665,7 @@ Rc::new(BindingsAccum { source_visible_names: env.source_visible_names.clone(), authored_import_names: env.authored_import_names.clone(), symbol_index: env.symbol_index.clone(), + unit_variant_index: stuck_accum.unit_variant_index.clone(), }), diagnostics: v1_rt::concat( diagnostics.clone(), @@ -22594,6 +22678,7 @@ Rc::new(BindingsAccum { Rc::new(BindingsAccum { bindings: env.bindings.clone(), str_bindings: env.str_bindings.clone(), + unit_variant_index: env.unit_variant_index.clone(), diagnostics: Rc::new(vec![]), }), |acc: Rc, name: String| { @@ -22620,22 +22705,14 @@ Rc::new(BindingsAccum { resolved: resolved.clone(), provenance: Rc::new(SubValueRelation::SubValueUnknown), }); - Rc::new(BindingsAccum { - bindings: v1_rt::rc_map_insert( - acc.bindings.clone(), - ident.clone(), - updated_binding.clone(), - ), - str_bindings: v1_rt::rc_map_insert( - acc.str_bindings.clone(), - name.clone(), - updated_binding.clone(), - ), - diagnostics: v1_rt::concat( - acc.diagnostics.clone(), - result.diagnostics.clone(), - ), - }) + bindings_accum_insert( + acc.clone(), + ident.clone(), + updated_binding.clone(), + env.parents.clone(), + env.source_indices.clone(), + result.diagnostics.clone(), + ) } None => acc.clone(), } @@ -22674,6 +22751,7 @@ Rc::new(BindingsAccum { source_visible_names: env.source_visible_names.clone(), authored_import_names: env.authored_import_names.clone(), symbol_index: env.symbol_index.clone(), + unit_variant_index: ready_accum.unit_variant_index.clone(), }); let __tco_2 = v1_rt::concat(diagnostics, ready_accum.diagnostics.clone()); let __tco_3 = (fuel - 1); @@ -23458,19 +23536,41 @@ pub fn rewire_type_env_import_str_binding_identity( local_names.clone(), inherited_keys.clone(), ); + let str_binding_overlay = rewire_str_binding_overlay( + m.type_env.clone().str_bindings.clone(), + rewrites.clone(), + ); let rewired = Rc::new(StrBindingsRewireAccum { str_bindings: v1_rt::rc_map_merge( m.type_env.clone().str_bindings.clone(), - rewire_str_binding_overlay( - m.type_env.clone().str_bindings.clone(), - rewrites.clone(), - ), + str_binding_overlay.clone(), ), ancestry_str_bindings: v1_rt::rc_map_merge( m.type_env.clone().ancestry_str_bindings.clone(), rewrites.clone(), ), }); + let rewired_index = Rc::new(v1_rt::map_values(&str_binding_overlay)) + .iter() + .cloned() + .fold( + m.type_env.clone().unit_variant_index.clone(), + |acc: Rc< + HashMap>>>, + >, + binding: Rc| { + crate::v1_compiler_infer_env::unit_variant_index_shadow_insert( + acc, + crate::v1_compiler_infer_env::effective_visible_binding( + m.type_env.clone().str_bindings.clone(), + m.type_env.clone().parents.clone(), + binding.name.clone(), + ), + binding.clone(), + source_indices.clone(), + ) + }, + ); Rc::new(TypedModule { progress: m.progress.clone(), module: m.module.clone(), @@ -23489,6 +23589,7 @@ pub fn rewire_type_env_import_str_binding_identity( source_visible_names: m.type_env.clone().source_visible_names.clone(), authored_import_names: m.type_env.clone().authored_import_names.clone(), symbol_index: m.type_env.clone().symbol_index.clone(), + unit_variant_index: rewired_index.clone(), }), type_env_cache: m.type_env_cache.clone(), interface: m.interface.clone(), @@ -23701,12 +23802,12 @@ pub fn compiler_kernel_type_env( ) }, ); + let kernel_str_bindings = + crate::v1_compiler_infer_env::str_bindings_from_bindings(kernel_bindings.clone()); Rc::new(TypeEnv { module_path: "".to_string(), bindings: kernel_bindings.clone(), - str_bindings: crate::v1_compiler_infer_env::str_bindings_from_bindings( - kernel_bindings.clone(), - ), + str_bindings: kernel_str_bindings.clone(), ancestry_str_bindings: v1_rt::rc_empty_map::>(), parents: Rc::new(vec![]), recursive_types: kernel_recursive_types.clone(), @@ -23717,6 +23818,11 @@ pub fn compiler_kernel_type_env( source_visible_names: v1_rt::rc_empty_map::(), authored_import_names: v1_rt::rc_empty_map::(), symbol_index: crate::v1_compiler_infer_env::empty_symbol_index(), + unit_variant_index: crate::v1_compiler_infer_env::build_unit_variant_index( + kernel_str_bindings.clone(), + Rc::new(vec![]), + source_indices.clone(), + ), }) } } @@ -23799,6 +23905,13 @@ pub fn rewire_type_env_parent_links( } __result }); + let rewired_parents = + v1_rt::concat(import_parents.clone(), Rc::new(vec![shared_kernel.clone()])); + let rewired_index = crate::v1_compiler_infer_env::build_unit_variant_index( + m.type_env.clone().str_bindings.clone(), + rewired_parents.clone(), + m.type_env.clone().source_indices.clone(), + ); Rc::new(TypedModule { progress: m.progress.clone(), module: m.module.clone(), @@ -23808,10 +23921,7 @@ pub fn rewire_type_env_parent_links( bindings: m.type_env.clone().bindings.clone(), str_bindings: m.type_env.clone().str_bindings.clone(), ancestry_str_bindings: m.type_env.clone().ancestry_str_bindings.clone(), - parents: v1_rt::concat( - import_parents.clone(), - Rc::new(vec![shared_kernel.clone()]), - ), + parents: rewired_parents.clone(), recursive_types: m.type_env.clone().recursive_types.clone(), recursive_type_set: m.type_env.clone().recursive_type_set.clone(), inductive_fields: m.type_env.clone().inductive_fields.clone(), @@ -23820,6 +23930,7 @@ pub fn rewire_type_env_parent_links( source_visible_names: m.type_env.clone().source_visible_names.clone(), authored_import_names: m.type_env.clone().authored_import_names.clone(), symbol_index: m.type_env.clone().symbol_index.clone(), + unit_variant_index: rewired_index.clone(), }), type_env_cache: m.type_env_cache.clone(), interface: m.interface.clone(), diff --git a/src/v1/stage0/src/v1_compiler_infer_env.rs b/src/v1/stage0/src/v1_compiler_infer_env.rs index dfbe3344020..68fe4480206 100644 --- a/src/v1/stage0/src/v1_compiler_infer_env.rs +++ b/src/v1/stage0/src/v1_compiler_infer_env.rs @@ -59,6 +59,7 @@ pub struct TypeEnv { pub authored_import_names: Rc>, pub symbol_index: Rc, pub module_path: String, + pub unit_variant_index: Rc>>>>, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -68,6 +69,214 @@ pub struct TypeBinding { pub provenance: Rc, } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct UnitVariantContribution { + pub count: i64, + pub variant: Rc, +} + +pub fn is_unit_variant_node(variant: Rc) -> bool { + ((variant.children.clone().len() as i64) == 0) +} + +pub fn variant_lookup_structural(ty: Rc) -> Rc { + if ((ty.connective.clone() == Connective::NoConnective) && (ty.inferred.clone() != None)) { + match ty.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: target, .. }) => target.clone(), + _ => ty, + } + } else { + ty + } +} + +pub fn binding_unit_variant_contributions( + binding: Rc, + source_indices: Rc>>, +) -> Rc>> { + { + let ty = variant_lookup_structural(binding.resolved.clone()); + match ty.connective.clone() { + Connective::Disj => ty.children.clone().iter().cloned().fold( + v1_rt::rc_empty_map::>(), + |acc: Rc>>, v: Rc| { + if is_unit_variant_node(v.clone()) { + { + let vname = crate::v1_std_core::authored_name_at( + source_indices.clone(), + v.clone(), + ); + match v1_rt::map_get(&acc, vname.clone()) { + Some(prev) => v1_rt::rc_map_insert( + acc.clone(), + vname.clone(), + Rc::new(UnitVariantContribution { + count: (prev.count.clone() + 1), + variant: prev.variant.clone(), + }), + ), + None => v1_rt::rc_map_insert( + acc.clone(), + vname.clone(), + Rc::new(UnitVariantContribution { + count: 1, + variant: v.clone(), + }), + ), + } + } + } else { + acc.clone() + } + }, + ), + _ => v1_rt::rc_empty_map::>(), + } + } +} + +pub fn contributions_without_key( + contribs: Rc>>, + key: String, +) -> Rc>> { + Rc::new(v1_rt::map_keys(&contribs)).iter().cloned().fold( + v1_rt::rc_empty_map::>(), + |acc: Rc>>, k: String| { + if (k.clone() == key.clone()) { + acc.clone() + } else { + match v1_rt::map_get(&contribs, k.clone()) { + Some(c) => v1_rt::rc_map_insert(acc.clone(), k.clone(), c.clone()), + None => acc.clone(), + } + } + }, + ) +} + +pub fn unit_variant_index_remove_binding( + index: Rc>>>>, + binding: Rc, + source_indices: Rc>>, +) -> Rc>>>> { + Rc::new(v1_rt::map_keys(&binding_unit_variant_contributions( + binding.clone(), + source_indices.clone(), + ))) + .iter() + .cloned() + .fold( + index.clone(), + |acc: Rc>>>>, + vname: String| match v1_rt::map_get(&acc, vname.clone()) { + Some(contribs) => v1_rt::rc_map_insert( + acc.clone(), + vname.clone(), + contributions_without_key(contribs.clone(), binding.name.clone()), + ), + None => acc.clone(), + }, + ) +} + +pub fn unit_variant_index_add_binding( + index: Rc>>>>, + binding: Rc, + source_indices: Rc>>, +) -> Rc>>>> { + { + let contributions = + binding_unit_variant_contributions(binding.clone(), source_indices.clone()); + Rc::new(v1_rt::map_keys(&contributions)) + .iter() + .cloned() + .fold( + index.clone(), + |acc: Rc>>>>, + vname: String| match v1_rt::map_get(&contributions, vname.clone()) + { + Some(contribution) => { + let contribs = match v1_rt::map_get(&acc, vname.clone()) { + Some(existing) => existing.clone(), + None => v1_rt::rc_empty_map::>(), + }; + v1_rt::rc_map_insert( + acc.clone(), + vname.clone(), + v1_rt::rc_map_insert( + contribs.clone(), + binding.name.clone(), + contribution.clone(), + ), + ) + } + None => acc.clone(), + }, + ) + } +} + +pub fn effective_visible_binding( + str_bindings: Rc>>, + parents: Rc>>, + name: String, +) -> Option> { + match v1_rt::map_get(&str_bindings, name.clone()) { + Some(b) => Some(b.clone()), + None => parents + .iter() + .cloned() + .fold(None, |acc: _, parent: Rc| { + if (acc.clone() != None) { + acc.clone() + } else { + v1_rt::map_get(&parent.str_bindings.clone(), name.clone()) + } + }), + } +} + +pub fn unit_variant_index_shadow_insert( + unit_variant_index: Rc>>>>, + shadowed: Option>, + binding: Rc, + source_indices: Rc>>, +) -> Rc>>>> { + { + let cleared = match shadowed.clone() { + Some(old) => unit_variant_index_remove_binding( + unit_variant_index.clone(), + old.clone(), + source_indices.clone(), + ), + None => unit_variant_index.clone(), + }; + unit_variant_index_add_binding(cleared.clone(), binding.clone(), source_indices.clone()) + } +} + +pub fn build_unit_variant_index( + str_bindings: Rc>>, + parents: Rc>>, + source_indices: Rc>>, +) -> Rc>>>> { + { + let visible = parents.iter().cloned().fold( + str_bindings.clone(), + |acc: Rc>>, parent: Rc| { + v1_rt::rc_map_merge(parent.str_bindings.clone(), acc) + }, + ); + Rc::new(v1_rt::map_values(&visible)).iter().cloned().fold( + v1_rt::rc_empty_map::>>>(), + |acc: Rc>>>>, + binding: Rc| { + unit_variant_index_add_binding(acc, binding.clone(), source_indices.clone()) + }, + ) + } +} + pub fn global_bare_fallback_invariant() -> String { thread_local! { static CACHED: String = { @@ -162,6 +371,10 @@ pub fn empty_type_env() -> Rc { source_visible_names: v1_rt::rc_empty_map::(), authored_import_names: v1_rt::rc_empty_map::(), symbol_index: empty_symbol_index(), + unit_variant_index: v1_rt::rc_empty_map::< + String, + Rc>>, + >(), }) } @@ -1960,6 +2173,17 @@ pub fn env_with_type_variable_bindings(env: Rc, tp_names: Rc, tp_names: Rc) -> bool { - ((variant.children.clone().len() as i64) == 0) -} - -pub fn unit_variant_in_coproduct( +pub fn lookup_unit_variant_phantom_type( env: Rc, - ty: Rc, variant_name: String, ) -> Option> { - match ty.connective.clone() { - Connective::Disj => { - ty.children - .clone() + match v1_rt::map_get(&env.unit_variant_index.clone(), variant_name.clone()) { + Some(contribs) => { + let total = Rc::new(v1_rt::map_values(&contribs)) .iter() .cloned() - .fold(None, |acc: _, v: Rc| { - if (acc.clone() != None) { - acc.clone() - } else { - if ((crate::v1_std_core::authored_name_at( - env.source_indices.clone(), - v.clone(), - ) == variant_name.clone()) - && is_unit_variant_node(v.clone())) - { - Some(v.clone()) - } else { - None + .fold(0, |acc: i64, c: Rc| { + (acc + c.count.clone()) + }); + if (total.clone() == 1) { + match Rc::new({ + let mut __result = Vec::new(); + for c in Rc::new(v1_rt::map_values(&contribs)).iter().cloned() { + if (c.count.clone() == 1) { + __result.push(c); } } + __result }) - } - _ => None, - } -} - -pub fn structural_type_for_variant_lookup(env: Rc, ty: Rc) -> Rc { - if ((ty.connective.clone() == Connective::NoConnective) && (ty.inferred.clone() != None)) { - match ty.inferred.clone().as_deref().cloned() { - Some(InferredNode::Resolved { node: target, .. }) => target.clone(), - _ => ty, - } - } else { - ty - } -} - -pub fn lookup_unit_variant_phantom_type( - env: Rc, - variant_name: String, -) -> Option> { - { - let matches = collect_unit_variant_phantom_matches(env.clone(), variant_name.clone()); - if ((matches.clone().len() as i64) == 1) { - match matches.clone().first().cloned() { - Some(variant) => Some(variant.clone()), - None => None, + .first() + .cloned() + { + Some(single) => Some(single.variant.clone()), + None => None, + } + } else { + None } - } else { - None } - } -} - -pub fn collect_unit_variant_phantom_matches( - env: Rc, - variant_name: String, -) -> Rc>> { - { - let direct_bindings = env.parents.clone().iter().cloned().fold( - env.str_bindings.clone(), - |acc: Rc>>, parent: Rc| { - v1_rt::rc_map_merge(parent.str_bindings.clone(), acc) - }, - ); - Rc::new(v1_rt::map_values(&direct_bindings)) - .iter() - .cloned() - .fold( - Rc::new(vec![]), - |acc: Rc>>, binding: Rc| match unit_variant_in_coproduct( - env.clone(), - structural_type_for_variant_lookup(env.clone(), binding.resolved.clone()), - variant_name.clone(), - ) { - Some(variant) => v1_rt::concat(acc.clone(), Rc::new(vec![variant.clone()])), - None => acc.clone(), - }, - ) + None => None, } }