diff --git a/dag/gunbc/recurring_failure_mode/an_imported_name_shadowed_by_a_kernel_name.dag b/dag/gunbc/recurring_failure_mode/an_imported_name_shadowed_by_a_kernel_name.dag new file mode 100644 index 00000000000..25bc7f243d6 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/an_imported_name_shadowed_by_a_kernel_name.dag @@ -0,0 +1,28 @@ +module gunbc.recurring_failure_mode.an_imported_name_shadowed_by_a_kernel_name + +import std.types { NonEmptyStr } +import std.decl_ref { DeclarationRef, WholeDeclaration } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data an_imported_name_shadowed_by_a_kernel_name: RecurringFailureMode = RecurringFailureMode { + identity: "an_imported_name_shadowed_by_a_kernel_name" as NonEmptyStr, + + receipts: [ + "an imported name shadowed by a kernel name -- residual after the Optional mint wall. v1.compiler.infer_env overlay_skips_kernel_name still sits above imports for the kernel types, the container spellings, Unit, Optional, Present, and Absent. lookup_binding still answers from env.bindings (declarations and named imports) before that overlay. INVALID STATE: one spelling, one module, two declarations, chosen by which lookup asks. The Optional instance of that fork is CLOSED: std.literal_elaboration kernel_named_import_standing / v1.compiler.resolve kernel_named_import_diags refuse a non-mint Optional import (gunbc.recurring_failure_mode.import_collides_with_a_kernel_name). The enrolled regression control is test.claim.infer_kernel_import_collision_witness importing_a_non_mint_optional_refuses_at_the_import (ImportCollidesWithKernelName). Names with no kernel_mint_declaration_rows row are KernelNamedImportAdmitted, so the two-lookup fork remains writable for every overlay_skips spelling that is not Optional.", + + "RESIDUAL POPULATION: overlay_skips_kernel_name minus the one minted name. kernel_type_set is String, Int, Bool, Float, Secret, Json, Unit, Bytes; containers ride is_container_type; Present and Absent are listed beside Optional. Only Optional has a mint row (std.optional Optional). A module that declares a type of any other overlay name and is imported by that name is still admitted on v1, and the overlay can still disagree with lookup_binding. Dual-representation imports (v2.std.text String via carrier_by_spelling) are a declared admitted population, not this class -- a second String is a carrier pair, not a silent mint leak. A rival Int, List, Present, or other overlay spelling that is not a dual-rep carrier is this class.", + + "HARM on the residual: silent wrongness (DESIGN section 5) wherever two readers take different paths on a non-mint overlay name. The Optional emit specimen (HeldChoice) is historical of the closed instance; it is not the current red. FOUND 2026-10-06 on gunbc#13454 as the Optional instance; retargeted 2026-10-07 (cursor review 77440) once that instance climbed.", + + "CURRENT RUNG: below the floor on the v1 residual -- the non-mint overlay import is still unrefused, so the two lookups can still disagree. The Optional path is mechanically preventable and is owned by import_collides_with_a_kernel_name; this row does not claim that rung. v2 already refuses an imported user Int at the reference (v2.test.claim.body_let_annotation bla_imported_user_int_refuses_rather_than_binding_the_kernel_int); that is a different class (kernel_type_spelling_captured_a_module_declaration) on a different compiler. ATTAINABLE CEILING: structurally guaranteed -- the residual collision is decidable at the import from overlay_skips_kernel_name and the mint-row set. NEXT-RUNG TRIGGER: the v1 import wall covers every overlay_skips spelling the same way Optional is covered (mint row or equivalent DeclarationRef ownership), except the declared dual-representation carriers, so a non-mint overlay import is unwritable and the two lookups can no longer disagree about it.", + ], + + evidence: [ + DeclarationRef { module_path: "v1.compiler.infer_env", decl_name: "overlay_skips_kernel_name", field: WholeDeclaration }, + DeclarationRef { module_path: "v1.compiler.infer_env", decl_name: "lookup_binding", field: WholeDeclaration }, + DeclarationRef { module_path: "std.literal_elaboration", decl_name: "kernel_named_import_standing", field: WholeDeclaration }, + DeclarationRef { module_path: "gunbc.structural_realization_bindings", decl_name: "kernel_mint_declaration_rows", field: WholeDeclaration }, + DeclarationRef { module_path: "gunbc.recurring_failure_mode.import_collides_with_a_kernel_name", decl_name: "import_collides_with_a_kernel_name", field: WholeDeclaration }, + DeclarationRef { module_path: "test.claim.infer_kernel_import_collision_witness", decl_name: "importing_a_non_mint_optional_refuses_at_the_import", field: WholeDeclaration }, + ], +} diff --git a/dag/gunbc/recurring_failure_mode/carrier_by_spelling.dag b/dag/gunbc/recurring_failure_mode/carrier_by_spelling.dag index 0360e6ee250..b8030b23ce8 100644 --- a/dag/gunbc/recurring_failure_mode/carrier_by_spelling.dag +++ b/dag/gunbc/recurring_failure_mode/carrier_by_spelling.dag @@ -8,7 +8,7 @@ data carrier_by_spelling: RecurringFailureMode = RecurringFailureMode { identity: "carrier_by_spelling" as NonEmptyStr, receipts: [ - "**carrier by spelling** (INVALID STATE: a module imports the structural text carrier `v2.std.text` `String` and then authors a BARE `String` as if that import bound it; KERNEL NAMES ARE NEVER OVERRIDDEN BY IMPORTS (`v1.compiler.infer` `overlay_skips_kernel_name`, kernel overlay unconditional since #9813), so the bare spelling binds the KERNEL host carrier beside the unused import.", + "**carrier by spelling** (INVALID STATE: a module imports the structural text carrier `v2.std.text` `String` and then authors a BARE `String` as if that import bound it; KERNEL NAMES ARE NEVER OVERRIDDEN BY IMPORTS (`v1.compiler.infer_env` `overlay_skips_kernel_name`, kernel overlay unconditional since #9813), so the bare spelling binds the KERNEL host carrier beside the unused import.", "A host-carrier value can therefore flow into a fold whose declared positions are the STRUCTURAL carrier, and the front end ACCEPTS the program.", @@ -46,7 +46,7 @@ data carrier_by_spelling: RecurringFailureMode = RecurringFailureMode { ], evidence: [ - DeclarationRef { module_path: "v1.compiler.infer", decl_name: "overlay_skips_kernel_name", field: WholeDeclaration }, + DeclarationRef { module_path: "v1.compiler.infer_env", decl_name: "overlay_skips_kernel_name", field: WholeDeclaration }, DeclarationRef { module_path: "gunbc.rust_source_type_bindings", decl_name: "checkpoint_row_migration_rows", field: WholeDeclaration }, DeclarationRef { module_path: "test.claim.self_host_structural_text_witness_test", decl_name: "w_bare_string_with_text_import_stays_host_deterministically", field: WholeDeclaration }, DeclarationRef { module_path: "gunbc.self_host_compile_phase_frontier", decl_name: "receipt_2_66765317_raw_error_diagnostic_identities", field: WholeDeclaration }, diff --git a/dag/gunbc/recurring_failure_mode/emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer.dag b/dag/gunbc/recurring_failure_mode/emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer.dag index 1fd72160761..e810aea1ccb 100644 --- a/dag/gunbc/recurring_failure_mode/emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer.dag +++ b/dag/gunbc/recurring_failure_mode/emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer.dag @@ -14,11 +14,11 @@ data emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer: RecurringFailur "SPECIMEN, the native approval broker closure (entry dag/gunbc/auth/approval_broker_serve.dag, lane 2A of the native-broker program, main fd30a502): std.access declares AccessRequest and gunbc.auth.access_request declares AccessRequest. v1.compiler.infer_emit_info add_emit_item_summary inserted both under `AccessRequest`; v1.compiler.trait_derive_emit v1_clone_bounded_type_params therefore held the one-element set Subject for that key, v1_item_clone_bounded_param_names filtered std.access's own [S, A, O, C, E] against it and found none, and std_access.rs printed `pub struct AccessRequest` over fields naming AccessContext and AccessEvidence: ten rustc errors (E0277, E0369). The paired control is the same emitter over dag/std/authorization_profile.dag, whose closure has one AccessRequest and prints all five bounds.", - "WHAT IS CLOSED AND WHAT IS NOT. The trait-derive family is re-keyed on the declaration -- v1.compiler.infer_emit_info TypeDeclIndex (EmitGraphInfo.type_decl_items), and with it clone_bounded_type_params, clone_impl_required_type_params and map_key_required_type_names -- under the item registry's own identity (v1.std.core callable_identity over owner module and declared name), and a reference reaches a row through resolve_type_decl_routed, whose spelling arm REFUSES a leaf two modules declare. STILL LEAF-KEYED, LAST WRITE WINS, on v1.compiler.infer_emit_info EmitGraphInfo: type_summaries (and its `Enum::Variant` rows), fn_decl_items, recursive_type_set, fielded_variants, positional_payload_variants, shared_types and variant_to_enum. data_variant_wire_spellings is keyed on the coproduct's leaf too but stores DataVariantSpellingRefused when two declarers disagree, so it fails closed; ownership_index and read_only_params_index are module-qualified and are not members.", + "WHAT IS CLOSED AND WHAT IS NOT. The trait-derive family is re-keyed on the declaration -- v1.compiler.infer_emit_info TypeDeclIndex (EmitGraphInfo.type_decl_items), and with it clone_bounded_type_params, clone_impl_required_type_params and map_key_required_type_names -- under the item registry's own identity (v1.std.core callable_identity over owner module and declared name), and a reference reaches a row through resolve_type_decl_routed, whose spelling arm REFUSES a leaf two modules declare. RE-KEYED IN A SECOND CUT: type_summaries is a TypeSummaryIndex keyed by the same declaration identity (variant-payload rows under `::`), and variant_to_enum maps each variant to its owner's identity, so a second same-leaf declaration no longer replaces the first's summary for readers in other modules (the unit row same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged). Readers that hold only a NAME read it through type_summary_decided, which answers no summary for a leaf two declarations own; that residue ends when TypeSummary's field_type_map and field_import_surface_names store identities. STILL LEAF-KEYED, LAST WRITE WINS, on v1.compiler.infer_emit_info EmitGraphInfo: fn_decl_items, recursive_type_set, fielded_variants, positional_payload_variants and shared_types. data_variant_wire_spellings is keyed on the coproduct's leaf too but stores DataVariantSpellingRefused when two declarers disagree, so it fails closed; ownership_index and read_only_params_index are module-qualified and are not members.", "A DECLARED MIDDLE STATE INSIDE THE CLOSED PART: kernel spellings. A kernel spelling (std.types is_kernel_type) is a reference resolve deliberately leaves unstamped, and the corpus also declares some of those leaves in two modules: v2.std.text and v2.std.node String, std.integer and v2.std.integer Int. Bool was a third until v2.std.logic Bool was retired; the arm is about any kernel-spelled leaf with two declarers, not about a fixed list. For such a reference the routed resolution answers TypeDeclKernelSpellingUndecided: it does NOT refuse, it derives no Clone or Ord bound from either declaration, and it carries a map-key requirement to EVERY declarer of the leaf, which is what the leaf-keyed set did. So for these leaves the emitted derives are unchanged by the re-keying and the question of which declaration a kernel-spelled position denotes is still open. Each occurrence is one row of v1.tests.claim.carrier_realization_census (emitter_decl_route). TRIGGER, at capability grain: resolve identifies a kernel-spelled reference -- as the kernel type or as the corpus declaration its scope binds -- at every type position the emitter reads; the owner is the text-boundary identity work (gunbc.rung_drop text_boundary_identity_wall), not the emitter. One stamped position does not retire the arm.", - "RUNG: for the trait-derive family, mechanically preventable -- gunbc.instruments.native_emission_controls (two ControlSlot declarations of different arity in one closure, emitted, built and run) and the unit row same_leaf_type_declarations_emit_their_own_bounds are the discriminating red and the positive control. For the seven indexes still leaf-keyed, mitigatable at best: the collision is observed only when rustc happens to refuse the foreign fact. ATTAINABLE CEILING: structurally impossible -- an index keyed on the declaration has no row two declarations can share. NEXT-RUNG TRIGGER, at capability grain: every EmitGraphInfo index that answers a question about a type declaration is keyed on the declaration's identity and reached from a reference through the one routed resolution, so that adding a same-leaf declaration to any module of a closure cannot change what is emitted for an existing one. Re-keying one more map is not that capability; the trigger is the set.", + "RUNG: for the trait-derive family, mechanically preventable -- gunbc.instruments.native_emission_controls (two ControlSlot declarations of different arity in one closure, emitted, built and run) and the unit row same_leaf_type_declarations_emit_their_own_bounds are the discriminating red and the positive control. For the five indexes still leaf-keyed, mitigatable at best: the collision is observed only when rustc happens to refuse the foreign fact. ATTAINABLE CEILING: structurally impossible -- an index keyed on the declaration has no row two declarations can share. NEXT-RUNG TRIGGER, at capability grain: every EmitGraphInfo index that answers a question about a type declaration is keyed on the declaration's identity and reached from a reference through the one routed resolution, so that adding a same-leaf declaration to any module of a closure cannot change what is emitted for an existing one. Re-keying one more map is not that capability; the trigger is the set.", ], evidence: [ diff --git a/dag/gunbc/rust_source_type_bindings.dag b/dag/gunbc/rust_source_type_bindings.dag index 4b01e3a906a..8f3ba6c12af 100644 --- a/dag/gunbc/rust_source_type_bindings.dag +++ b/dag/gunbc/rust_source_type_bindings.dag @@ -135,7 +135,7 @@ fn checkpoint_row_migration_rows() -> List { CheckpointRowMigration { dag_name: "String" as NonEmptyStr, disposition: ProvenUniqueKernelBinding { - proof: "The kernel string_type is minted by v1.compiler.types for every string literal and carries no declaration; both .dag declarations of the spelling (v2.std.text, std.string_type) are gated structural by v1.compiler.coercion structural_declaration_modules_for and never reach this row. THE VERDICT STANDS AND ITS ORIGINAL ARGUMENT WAS EXACTLY INVERTED, corrected here rather than softened because the inverted form would justify the wrong things if reused. It read: the bare spelling cannot be captured because the only import that could shadow it binds the SAME token, so in a module importing v2.std.text String every `String` reference IS the text carrier and the kernel spelling is unreachable there. The opposite is true. KERNEL NAMES ARE NEVER OVERRIDDEN BY IMPORTS (v1.compiler.infer direct_import_export_precedence_note, overlay_skips_kernel_name), so in such a module the import does not shadow at all and a bare `String` is ALWAYS the kernel -- the spelling the old argument called unreachable is the only one you reach. Three routes exist and all three are sound for this row: a bare reference in an importing module resolves to the kernel and IS this row's binding; a bare reference INSIDE v2.std.text resolves LOCALLY (locals beat kernel) and is gated structural, never reaching the row; and a QUALIFIED v2.std.text.String resolves through the alias to the dotted name std.algebra.FreeMonoid, which matches no bare row. Symbol was captured precisely because its token differed from its spelling, and that clause survives unchanged. ESTABLISHED BY EXECUTION, not by reading precedence -- AND THE SUBJECT NAMED HERE IS CORRECTED: this sentence previously said the census was run over A FIXTURE MODULE importing both v2.std.text String and v2.std.node Node. IT WAS NOT. The receipts carry no fixture rows at all; the subjects were LIVE CORPUS MODULES, and naming a subject that was not run is the same citation defect this row exists to correct. What v1.tests.claim.carrier_realization_census actually reports: in std.algebra, a module that imports the spelling, a bare String carries the kernel identity at declaration_field AND at fn_signature_param; inside v2.std.text the same spelling carries its own declaring module and diverges with exact identity, which is route 2 executed rather than argued; and v2.std.node Node carries its real declaring module at both position kinds as the positive control. RE-DERIVATION IS POSITION-KIND SENSITIVE AND THE OBVIOUS INSTRUCTION IS A TRAP. Running that census over a closure re-derives routes 1 and 2 soundly. It does NOT re-derive route 3: at fn_signature_param the census resolves a QUALIFIED v2.std.text.String through the alias onto the alias declaration's own name, which is the spelling String, and attributes it to -- confidently naming the very carrier the qualification was written to move away from. That is measured by vivid-deer-102 and filed as recurring failure mode alias_resolution_collides_with_kernel_spelling (gunbc#9939); the same instrument is correct for qualified aliases at declaration_field. ROUTE 3 THEREFORE RESTS ON STRUCTURAL RESOLUTION PLUS A RUSTC MEASUREMENT -- the emitted crate carries an E0308 on the bare arm and not on the qualified one -- and explicitly NOT on this census, which cannot answer at that position. The instrument is named rather than its rows transcribed (DESIGN section 6). SINCE gunbc#12760 THE KERNEL HOST TEXT HAS A DECLARATION: v2.std.node String, opaque, with its own exact row above (RustStdString). So the kernel spelling now has one declaration, and this bare row and that exact row render the same carrier, std::string::String; the uniqueness this row proves is unchanged." as NonEmptyStr + proof: "The kernel string_type is minted by v1.compiler.types for every string literal and carries no declaration; both .dag declarations of the spelling (v2.std.text, std.string_type) are gated structural by v1.compiler.coercion structural_declaration_modules_for and never reach this row. THE VERDICT STANDS AND ITS ORIGINAL ARGUMENT WAS EXACTLY INVERTED, corrected here rather than softened because the inverted form would justify the wrong things if reused. It read: the bare spelling cannot be captured because the only import that could shadow it binds the SAME token, so in a module importing v2.std.text String every `String` reference IS the text carrier and the kernel spelling is unreachable there. The opposite is true. KERNEL NAMES ARE NEVER OVERRIDDEN BY IMPORTS (v1.compiler.infer direct_import_export_precedence_note; v1.compiler.infer_env overlay_skips_kernel_name), so in such a module the import does not shadow at all and a bare `String` is ALWAYS the kernel -- the spelling the old argument called unreachable is the only one you reach. Three routes exist and all three are sound for this row: a bare reference in an importing module resolves to the kernel and IS this row's binding; a bare reference INSIDE v2.std.text resolves LOCALLY (locals beat kernel) and is gated structural, never reaching the row; and a QUALIFIED v2.std.text.String resolves through the alias to the dotted name std.algebra.FreeMonoid, which matches no bare row. Symbol was captured precisely because its token differed from its spelling, and that clause survives unchanged. ESTABLISHED BY EXECUTION, not by reading precedence -- AND THE SUBJECT NAMED HERE IS CORRECTED: this sentence previously said the census was run over A FIXTURE MODULE importing both v2.std.text String and v2.std.node Node. IT WAS NOT. The receipts carry no fixture rows at all; the subjects were LIVE CORPUS MODULES, and naming a subject that was not run is the same citation defect this row exists to correct. What v1.tests.claim.carrier_realization_census actually reports: in std.algebra, a module that imports the spelling, a bare String carries the kernel identity at declaration_field AND at fn_signature_param; inside v2.std.text the same spelling carries its own declaring module and diverges with exact identity, which is route 2 executed rather than argued; and v2.std.node Node carries its real declaring module at both position kinds as the positive control. RE-DERIVATION IS POSITION-KIND SENSITIVE AND THE OBVIOUS INSTRUCTION IS A TRAP. Running that census over a closure re-derives routes 1 and 2 soundly. It does NOT re-derive route 3: at fn_signature_param the census resolves a QUALIFIED v2.std.text.String through the alias onto the alias declaration's own name, which is the spelling String, and attributes it to -- confidently naming the very carrier the qualification was written to move away from. That is measured by vivid-deer-102 and filed as recurring failure mode alias_resolution_collides_with_kernel_spelling (gunbc#9939); the same instrument is correct for qualified aliases at declaration_field. ROUTE 3 THEREFORE RESTS ON STRUCTURAL RESOLUTION PLUS A RUSTC MEASUREMENT -- the emitted crate carries an E0308 on the bare arm and not on the qualified one -- and explicitly NOT on this census, which cannot answer at that position. The instrument is named rather than its rows transcribed (DESIGN section 6). SINCE gunbc#12760 THE KERNEL HOST TEXT HAS A DECLARATION: v2.std.node String, opaque, with its own exact row above (RustStdString). So the kernel spelling now has one declaration, and this bare row and that exact row render the same carrier, std::string::String; the uniqueness this row proves is unchanged." as NonEmptyStr } }, CheckpointRowMigration { diff --git a/src/v1/04_emit_info.dag b/src/v1/04_emit_info.dag index bd401957bea..70c649484d2 100644 --- a/src/v1/04_emit_info.dag +++ b/src/v1/04_emit_info.dag @@ -21,7 +21,9 @@ import v1.std.core { } import std.decl_ref { DeclarationRef, WholeDeclaration, NamedField, TypeParameter } import std.types { is_kernel_type } -import v1.compiler.infer_env { TypeEnv, SymbolIndex, empty_symbol_index, empty_type_env, symbol_index_lookup } +import std.literal_elaboration { kernel_mint_declaration_for, KernelMintDeclarationFound, KernelMintDeclarationAbsent, KernelMintDeclarationAmbiguous } +import gunbc.structural_realization_bindings { kernel_mint_declaration_rows } +import v1.compiler.infer_env { TypeEnv, SymbolIndex, empty_symbol_index, empty_type_env, symbol_index_lookup, BareOccurrenceBinding, BareOccurrenceDeclaredInItsFile, BareOccurrenceImportedByName, BareOccurrenceIsKernelName, BareOccurrenceUndecided, bare_occurrence_binding } import v1.compiler.infer_types { TextJudgment, TextJudgedIn, TextNotAsked, TextNotAskedInVariantFieldSummary, TextNotAskedForCallableComponentResidue, normalize_access_type_node, resolved_type, @@ -40,6 +42,7 @@ type TypeRepr = StructRepr | EnumRepr { unit_only: Bool } type TypeSummary { name: String + key: String repr: TypeRepr field_summaries: Map field_type_map: Map @@ -49,6 +52,122 @@ type TypeSummary { has_fn_fields: Bool } +// THE TYPE SUMMARIES, KEYED BY DECLARATION. A summary is stored under its declaration's identity +// (type_decl_identity: owner module and declared name, the key TypeDeclIndex uses), and a +// variant-payload summary under `::`. The leaf-keyed map this replaces kept ONE +// summary per leaf -- whichever module was folded last -- so a second `Optional` anywhere in a +// closure replaced std.optional's summary for every reader in every module +// (gunbc.recurring_failure_mode emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer). +type TypeSummaryIndex { + by_key: Map + keys_by_leaf: Map> +} + +// A NAME HOLDER'S ANSWER HAS THREE ARMS, as TypeDeclResolution's does: a key (an identity, or an +// identity-qualified variant key) is exact; a bare leaf one declaration owns resolves to it; a bare +// leaf two declarations own is TypeSummaryLeafAmbiguous and names neither. +type TypeSummaryLookup + = TypeSummaryFound { summary: TypeSummary } + | TypeSummaryLeafAmbiguous { leaf: String } + | TypeSummaryNotDeclared + +fn empty_type_summary_index() -> TypeSummaryIndex { + TypeSummaryIndex { by_key: empty_map(), keys_by_leaf: empty_map() } +} + +fn type_summary_index_insert(index: TypeSummaryIndex, key: String, leaf: String, summary: TypeSummary) -> TypeSummaryIndex { + TypeSummaryIndex { + by_key: map_insert(index.by_key, key, summary), + keys_by_leaf: map_insert(index.keys_by_leaf, leaf, type_decl_leaf_identities_with(prior: map_get(index.keys_by_leaf, leaf), identity: key)) + } +} + +fn type_summary_keys_of_leaf(index: TypeSummaryIndex, leaf: String) -> List { + match map_get(index.keys_by_leaf, leaf) { + Present { value: keys } => keys + Absent => [] + } +} + +fn type_summary_at_key(index: TypeSummaryIndex, key: String) -> TypeSummaryLookup { + match map_get(index.by_key, key) { + Present { value: summary } => TypeSummaryFound { summary: summary } + Absent => TypeSummaryNotDeclared + } +} + +fn type_summary_by_leaf(index: TypeSummaryIndex, leaf: String) -> TypeSummaryLookup { + let keys = type_summary_keys_of_leaf(index: index, leaf: leaf) + if (keys |> count) == 1 { + keys |> fold(init: TypeSummaryNotDeclared, f: (_acc, key) => type_summary_at_key(index: index, key: key)) + } else if (keys |> count) > 1 { + TypeSummaryLeafAmbiguous { leaf: leaf } + } else { + TypeSummaryNotDeclared + } +} + +// A string key, as the readers that hold only a name hand it over: an exact key first (an identity, +// or `::`), then a leaf-qualified variant key (`Enum::Variant`, whose enum part +// resolves by its leaf), then a bare leaf. A dotted name that is no key is not resolved by spelling. +fn type_summary_lookup(index: TypeSummaryIndex, key: String) -> TypeSummaryLookup { + match map_get(index.by_key, key) { + Present { value: summary } => TypeSummaryFound { summary: summary } + Absent => + if contains(key, "::") { + let parts = key |> split(delimiter: "::") + let enum_part = parts |> take((parts |> count) - 1) |> join(separator: "::") + let variant_part = match parts |> last { + Present { value: v } => v + Absent => "" + } + match type_summary_lookup(index: index, key: enum_part) { + TypeSummaryFound { summary: owner } => type_summary_at_key(index: index, key: variant_summary_key(enum_name: owner.key, variant_name: variant_part)) + TypeSummaryLeafAmbiguous { leaf: l } => TypeSummaryLeafAmbiguous { leaf: l } + TypeSummaryNotDeclared => TypeSummaryNotDeclared + } + } else if contains(key, ".") { + TypeSummaryNotDeclared + } else { + type_summary_by_leaf(index: index, leaf: key) + } + } +} + +// A reader holding a type REFERENCE resolves it the way every emitter reader of a declaration does +// (resolve_type_decl_reference: carried identity, declaring span, the counted interim arms, then the +// spelling), and reads the summary stored under that identity. +fn type_summary_of_reference(index: TypeSummaryIndex, decls: TypeDeclIndex, type_expr: Node, source_indices: Map) -> TypeSummaryLookup { + match resolve_type_decl_reference(index: decls, type_expr: type_expr, source_indices: source_indices) { + TypeDeclResolved { identity: identity, decl: _ } => type_summary_at_key(index: index, key: identity) + TypeDeclLeafAmbiguous { leaf: l } => TypeSummaryLeafAmbiguous { leaf: l } + TypeDeclKernelSpellingUndecided { leaf: l } => TypeSummaryLeafAmbiguous { leaf: l } + TypeDeclNotDeclared => TypeSummaryNotDeclared + } +} + +// THE OPTIONAL PROJECTION, for readers that hold only a NAME and ask which summary it denotes in order +// to collect use-surfaces or read a field map. It answers a summary only when the name decides one +// (an exact key, or a leaf one declaration owns); a leaf two declarations own answers Absent and no +// summary is picked for it -- the leaf-keyed map this replaces answered with the LAST declarer here. +// The readers that consume it collect names for import lines or check a repr, so an undecided name +// contributes nothing and the item it would have served refuses at rustc, located at its use. +// RESIDUE, declared: these name-holding readers dissolve when the names they hold are keys -- a +// TypeSummary's field_type_map and field_import_surface_names store the field type's declaration +// identity rather than its spelling -- on gunbc.recurring_failure_mode +// emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer's trigger. +fn type_summary_decided(index: TypeSummaryIndex, key: String) -> TypeSummary? { + match type_summary_lookup(index: index, key: key) { + TypeSummaryFound { summary: summary } => Present { value: summary } + TypeSummaryLeafAmbiguous { leaf: _ } => none + TypeSummaryNotDeclared => none + } +} + +fn type_summary_values(index: TypeSummaryIndex) -> List { + map_values(index.by_key) +} + type FieldTypeMapBuild { field_types: Map import_surface_names: List @@ -158,6 +277,15 @@ type TypeDeclIndex { qualified_names: SymbolIndex } +// WHAT A BARE LEAF DENOTES AT ONE OCCURRENCE: v1.compiler.infer_env bare_occurrence_binding (own file, +// then named import, then kernel -- the typechecker's lookup_binding order), joined here to the +// declaration identity this index keys on. +type TypeDeclOccurrenceBinding + = OccurrenceDeclaredHere { identity: String } + | OccurrenceImported { identity: String } + | OccurrenceIsKernelName + | OccurrenceUndecided + // TypeDeclKernelSpellingUndecided IS ITS OWN ARM BECAUSE IT IS A DIFFERENT FACT FROM AMBIGUITY. // `String` and `Int` are kernel spellings (std.types is_kernel_type), and resolve leaves a // kernel-spelled reference unstamped on purpose (v1.compiler.infer_resolve @@ -263,6 +391,8 @@ type TypeDeclReferenceRoute | RouteDeclaringSpan | RouteReferencingModuleDeclarer | RouteQualifiedSpelling + | RouteReferencingModuleImport + | RouteKernelMint | RouteLeafSpelling type TypeDeclRoutedResolution { @@ -292,13 +422,15 @@ fn resolve_type_decl_routed(index: TypeDeclIndex, type_expr: Node, source_indice let leaf = qualified_last_segment(name: authored) let by_spelling = resolve_type_decl_leaf(index: index, leaf: leaf) let referencing_module_identity = match by_spelling { - TypeDeclLeafAmbiguous { leaf: l } => if authored == l { type_decl_referencing_module_declarer(index: index, leaf: l, reference: type_expr) } else { type_decl_qualifier_declarer(index: index, authored: authored) } + TypeDeclLeafAmbiguous { leaf: l } => + if authored == l { type_decl_occurrence_identity(index: index, leaf: l, reference: type_expr) } + else { type_decl_qualifier_declarer(index: index, authored: authored) } TypeDeclResolved { identity: _, decl: _ } => none TypeDeclKernelSpellingUndecided { leaf: _ } => none TypeDeclNotDeclared => none } match referencing_module_identity { - Present { value: identity } => TypeDeclRoutedResolution { route: if authored == leaf { RouteReferencingModuleDeclarer } else { RouteQualifiedSpelling }, resolution: type_decl_resolution_at_identity(index: index, identity: identity) } + Present { value: identity } => TypeDeclRoutedResolution { route: type_decl_spelling_route(index: index, authored: authored, leaf: leaf, reference: type_expr), resolution: type_decl_resolution_at_identity(index: index, identity: identity) } Absent => TypeDeclRoutedResolution { route: RouteLeafSpelling, resolution: by_spelling } } } @@ -341,22 +473,84 @@ fn type_decl_qualifier_declarer(index: TypeDeclIndex, authored: String) -> Strin } } -fn type_decl_index_with_qualified_names(index: TypeDeclIndex, qualified_names: SymbolIndex) -> TypeDeclIndex { - TypeDeclIndex { by_identity: index.by_identity, identity_by_declaring_span: index.identity_by_declaring_span, leaf_owners: index.leaf_owners, identities_by_leaf: index.identities_by_leaf, qualified_names: qualified_names } +// THE KERNEL MINT'S DECLARER. Which corpus declaration the kernel type IS is a modeled fact +// (gunbc.structural_realization_bindings kernel_mint_declaration_rows, the row the pattern side reads +// through kernel_mint_ownership), but that answers WHICH declaration a mint stands for, not WHETHER an +// occurrence denotes it. So this arm is reached only from type_decl_occurrence_identity, and only when +// the occurrence is on the kernel arm of the resolver's order (v1.compiler.infer_env bare_occurrence_binding). A spelling no row mints, or two rows +// mint, stays LeafAmbiguous and refuses. Counted as kernel_mint; interim under +// referencing_module_declarer_route_dissolves_on. +fn type_decl_kernel_mint_declarer(index: TypeDeclIndex, leaf: String) -> String? { + match kernel_mint_declaration_for(rows: kernel_mint_declaration_rows, minted_name: leaf) { + KernelMintDeclarationFound { declaration: d } => + let identity = type_decl_identity(owner_module: d.module_path as String, decl_name: d.decl_name as String) + match map_get(index.by_identity, identity) { + Present { value: _ } => Present { value: identity } + Absent => none + } + KernelMintDeclarationAbsent => none + KernelMintDeclarationAmbiguous { row_count: _ } => none + } } -data referencing_module_declarer_route_dissolves_on: DissolutionCondition = unbound_dissolution(description: "RouteReferencingModuleDeclarer and RouteQualifiedSpelling dissolve when the type environment's declaration bodies carry Node.declaration on every member type reference, stamped by v1.compiler.infer_resolve reference_with_declaration in the DECLARING module's scope, so a bare reference resolved through lookup_type_for hands the emitter stamped members: v1.tests.claim.carrier_realization_census reports zero emitter_decl_route referencing_module_declarer or qualified_spelling rows over the self-host and dag closures. Stamping one declaration, or one closure, is not that capability. Then both arms, type_decl_referencing_module_declarer and type_decl_qualifier_declarer are deleted and such a reference refuses unless carried.") - -fn type_decl_referencing_module_declarer(index: TypeDeclIndex, leaf: String, reference: Node) -> String? { - let local = type_decl_identities_of_leaf(index: index, leaf: leaf) |> filter(identity => - match map_get(index.by_identity, identity) { - Present { value: decl } => decl.span.file == reference.span.file - Absent => false +fn type_decl_spelling_route(index: TypeDeclIndex, authored: String, leaf: String, reference: Node) -> TypeDeclReferenceRoute { + if authored != leaf { RouteQualifiedSpelling } + else { + match type_decl_occurrence_binding(index: index, leaf: leaf, reference: reference) { + OccurrenceDeclaredHere { identity: _ } => RouteReferencingModuleDeclarer + OccurrenceIsKernelName => RouteKernelMint + OccurrenceImported { identity: _ } => RouteReferencingModuleImport + OccurrenceUndecided => RouteLeafSpelling } - ) - if (local |> fold(init: 0, f: (n, _identity) => n + 1)) == 1 { local |> fold(init: none, f: (acc, identity) => Present { value: identity }) } else { none } + } +} + +// THE IDENTITY A BARE AMBIGUOUS LEAF DENOTES AT THIS OCCURRENCE, or none (it stays LeafAmbiguous and +// refuses). The kernel mint is consulted only on the kernel arm of the resolver's order. +fn type_decl_occurrence_identity(index: TypeDeclIndex, leaf: String, reference: Node) -> String? { + match type_decl_occurrence_binding(index: index, leaf: leaf, reference: reference) { + OccurrenceDeclaredHere { identity: identity } => Present { value: identity } + OccurrenceIsKernelName => type_decl_kernel_mint_declarer(index: index, leaf: leaf) + OccurrenceImported { identity: identity } => Present { value: identity } + OccurrenceUndecided => none + } } +fn type_decl_occurrence_binding(index: TypeDeclIndex, leaf: String, reference: Node) -> TypeDeclOccurrenceBinding { + match bare_occurrence_binding(index: index.qualified_names, name: leaf, reference: reference) { + BareOccurrenceDeclaredInItsFile { declaration: decl } => + match type_decl_identity_of_declaration(index: index, decl: decl) { + Present { value: identity } => OccurrenceDeclaredHere { identity: identity } + Absent => OccurrenceUndecided + } + BareOccurrenceImportedByName { module_path: from_module, declaration: decl } => + match type_decl_identity_of_declaration(index: index, decl: decl) { + Present { value: identity } => OccurrenceImported { identity: identity } + Absent => + let imported = type_decl_identity(owner_module: from_module, decl_name: leaf) + match map_get(index.by_identity, imported) { + Present { value: _ } => OccurrenceImported { identity: imported } + Absent => OccurrenceUndecided + } + } + BareOccurrenceIsKernelName => OccurrenceIsKernelName + BareOccurrenceUndecided => OccurrenceUndecided + } +} + +fn type_decl_identity_of_declaration(index: TypeDeclIndex, decl: Node) -> String? { + match decl.ident_span { + Present { value: sp } => map_get(index.identity_by_declaring_span, declaring_span_key(sp: sp)) + Absent => none + } +} + +fn type_decl_index_with_qualified_names(index: TypeDeclIndex, qualified_names: SymbolIndex) -> TypeDeclIndex { + TypeDeclIndex { by_identity: index.by_identity, identity_by_declaring_span: index.identity_by_declaring_span, leaf_owners: index.leaf_owners, identities_by_leaf: index.identities_by_leaf, qualified_names: qualified_names } +} + +data referencing_module_declarer_route_dissolves_on: DissolutionCondition = unbound_dissolution(description: "RouteReferencingModuleDeclarer, RouteReferencingModuleImport, RouteQualifiedSpelling and RouteKernelMint dissolve when the type environment's declaration bodies carry Node.declaration on every member type reference, stamped by v1.compiler.infer_resolve reference_with_declaration in the DECLARING module's scope, so a bare reference resolved through lookup_type_for hands the emitter stamped members: v1.tests.claim.carrier_realization_census reports zero emitter_decl_route referencing_module_declarer, referencing_module_import, qualified_spelling or kernel_mint rows over the self-host and dag closures. Stamping one declaration, or one closure, is not that capability. Then type_decl_occurrence_binding and type_decl_qualifier_declarer are deleted and such a reference refuses unless carried.") + fn resolve_type_decl_reference(index: TypeDeclIndex, type_expr: Node, source_indices: Map) -> TypeDeclResolution { resolve_type_decl_routed(index: index, type_expr: type_expr, source_indices: source_indices).resolution } @@ -368,6 +562,8 @@ fn type_decl_routed_resolution_label(routed: TypeDeclRoutedResolution) -> String RouteDeclaringSpan => "declaring_span" RouteReferencingModuleDeclarer => "referencing_module_declarer" RouteQualifiedSpelling => "qualified_spelling" + RouteReferencingModuleImport => "referencing_module_import" + RouteKernelMint => "kernel_mint" RouteLeafSpelling => "leaf_spelling" } match routed.resolution { @@ -379,7 +575,7 @@ fn type_decl_routed_resolution_label(routed: TypeDeclRoutedResolution) -> String } type EmitGraphInfo { - type_summaries: Map + type_summaries: TypeSummaryIndex type_decl_items: TypeDeclIndex data_variant_wire_spellings: Map fn_decl_items: Map @@ -409,7 +605,7 @@ type EmitGraphInfo { } type EmitInfoBuildState { - type_summaries: Map + type_summaries: TypeSummaryIndex type_decl_items: TypeDeclIndex fn_decl_items: Map structural_alias_fn_surface_names: Map> @@ -419,7 +615,7 @@ type EmitInfoBuildState { fn empty_emit_graph_info() -> EmitGraphInfo { EmitGraphInfo { item_leaf_owner_modules: empty_map(), - type_summaries: empty_map(), + type_summaries: empty_type_summary_index(), type_decl_items: empty_type_decl_index(), data_variant_wire_spellings: empty_map(), fn_decl_items: empty_map(), @@ -540,7 +736,34 @@ fn variant_summary_key(enum_name: String, variant_name: String) -> String { } fn lookup_emit_type_summary(emit_info: EmitGraphInfo, type_name: String) -> TypeSummary? { - map_get(emit_info.type_summaries, type_name) + type_summary_decided(index: emit_info.type_summaries, key: type_name) +} + +// A YES/NO QUESTION ABOUT A NAME. Unanimous answers from every declaration of a leaf are decided. +// Disagreement is not "no": collapsing it to false made `is this an enum?` emit the non-enum arm +// for a name two declarations own, which rustc can accept. NotDeclared is a separate arm so a +// missing name is not an ambiguous one. +type TypeSummaryQuestion + = QuestionDecided { value: Bool } + | QuestionNameAmbiguous { leaf: String } + | QuestionNotDeclared + +fn type_summary_answer(index: TypeSummaryIndex, key: String, question: fn(TypeSummary) -> Bool) -> TypeSummaryQuestion { + match type_summary_lookup(index: index, key: key) { + TypeSummaryFound { summary: summary } => QuestionDecided { value: question(summary) } + TypeSummaryNotDeclared => QuestionNotDeclared + TypeSummaryLeafAmbiguous { leaf: leaf } => + let answers = type_summary_keys_of_leaf(index: index, leaf: leaf) |> fold(init: [], f: (acc, k) => + match map_get(index.by_key, k) { + Present { value: summary } => list_push(acc, question(summary)) + Absent => acc + } + ) + if (answers |> count) == 0 { QuestionNotDeclared } + else if answers |> all(a => a) { QuestionDecided { value: true } } + else if answers |> all(a => !a) { QuestionDecided { value: false } } + else { QuestionNameAmbiguous { leaf: leaf } } + } } fn emit_graph_records_type_decl(item: Node, source_indices: Map) -> Bool { @@ -565,14 +788,17 @@ fn emit_graph_records_fn_decl(item: Node) -> Bool { item.module_item_kind == ModuleItemFunction } -fn derive_variant_to_enum(type_summaries: Map) -> Map { - map_values(type_summaries) |> fold(init: empty_map(), f: (acc, summary) => +// variant leaf -> the KEY of the enum that declares it, or "" when two enums declare that variant. +// The value is the owner's identity, not its leaf: two same-leaf enums own different variants, and a +// leaf value would send every reader back through the ambiguous spelling. +fn derive_variant_to_enum(type_summaries: TypeSummaryIndex) -> Map { + type_summary_values(index: type_summaries) |> fold(init: empty_map(), f: (acc, summary) => match summary.repr { EnumRepr { unit_only: _ } => fold(map_keys(summary.variant_name_set), init: acc, f: (inner, vn) => match map_get(inner, vn) { Present { value: _ } => map_insert(inner, vn, "") - Absent => map_insert(inner, vn, summary.name) + Absent => map_insert(inner, vn, summary.key) } ) _ => acc @@ -580,8 +806,8 @@ fn derive_variant_to_enum(type_summaries: Map) -> Map, name: String) -> Bool { - map_values(type_summaries) |> any(summary => +fn is_known_variant(type_summaries: TypeSummaryIndex, name: String) -> Bool { + type_summary_values(index: type_summaries) |> any(summary => match summary.repr { EnumRepr { unit_only: _ } => emit_map_has(m: summary.variant_name_set, key: name) _ => false @@ -589,32 +815,44 @@ fn is_known_variant(type_summaries: Map, name: String) -> B ) } -fn variant_belongs_to_enum(type_summaries: Map, variant_name: String, enum_name: String) -> Bool { - match map_get(type_summaries, enum_name) { - Present { value: summary } => - match summary.repr { - EnumRepr { unit_only: _ } => - emit_map_has(m: summary.variant_name_set, key: variant_name) - _ => false - } - Absent => false +fn summary_is_enum_with_variant(summary: TypeSummary, variant_name: String) -> Bool { + match summary.repr { + EnumRepr { unit_only: _ } => emit_map_has(m: summary.variant_name_set, key: variant_name) + _ => false } } -fn is_enum_in_summaries(type_summaries: Map, type_name: String) -> Bool { - match map_get(type_summaries, type_name) { - Present { value: summary } => match summary.repr { - EnumRepr { unit_only: _ } => true - _ => false - } - Absent => false +fn summary_is_enum(summary: TypeSummary) -> Bool { + match summary.repr { + EnumRepr { unit_only: _ } => true + _ => false } } -fn find_variant_parent(type_summaries: Map, variant_name: String, scope_enums: List) -> String? { - scope_enums |> filter(en => - variant_belongs_to_enum(type_summaries: type_summaries, variant_name: variant_name, enum_name: en) - ) |> first +fn variant_belongs_to_enum(type_summaries: TypeSummaryIndex, variant_name: String, enum_name: String) -> TypeSummaryQuestion { + type_summary_answer(index: type_summaries, key: enum_name, question: summary => summary_is_enum_with_variant(summary: summary, variant_name: variant_name)) +} + +fn is_enum_in_summaries(type_summaries: TypeSummaryIndex, type_name: String) -> TypeSummaryQuestion { + type_summary_answer(index: type_summaries, key: type_name, question: summary => summary_is_enum(summary: summary)) +} + +fn find_variant_parent(type_summaries: TypeSummaryIndex, variant_name: String, scope_enums: List) -> String? { + if scope_enums |> any(en => + match variant_belongs_to_enum(type_summaries: type_summaries, variant_name: variant_name, enum_name: en) { + QuestionNameAmbiguous { leaf: _ } => true + _ => false + } + ) { + none + } else { + scope_enums |> filter(en => + match variant_belongs_to_enum(type_summaries: type_summaries, variant_name: variant_name, enum_name: en) { + QuestionDecided { value: v } => v + _ => false + } + ) |> first + } } fn field_value_shape_from_type_node(type_node: Node) -> FieldValueShape { @@ -735,6 +973,7 @@ fn build_type_summary(item: Node, source_indices: Map) -> let field_types = build_field_type_map(children: item.children, source_indices: source_indices) Present { value: TypeSummary { name: authored_name_at(source_indices: source_indices, node: item), + key: "", repr: StructRepr, field_summaries: build_struct_field_summaries(parent: item, source_indices: source_indices), field_type_map: field_types.field_types, @@ -747,6 +986,7 @@ fn build_type_summary(item: Node, source_indices: Map) -> let unit_only = item.children |> all(child => child.children |> count == 0) Present { value: TypeSummary { name: authored_name_at(source_indices: source_indices, node: item), + key: "", repr: EnumRepr { unit_only: unit_only }, field_summaries: build_enum_field_summaries(variants: item.children, source_indices: source_indices), field_type_map: empty_map(), @@ -805,15 +1045,26 @@ type FnReachRound { grew: Bool } -fn fn_reach_holds_directly(name: String, summaries: Map, structural_alias_direct_fn_names: Set) -> Bool { - match map_get(summaries, name) { +// The walk is over summary KEYS. A field names its type by spelling, so a target resolves to the +// key it names exactly, or to EVERY declarer of that leaf: reachability is then an over-approximation +// computed as the answer (a type reaching a function value through either same-leaf declaration is +// marked), and the spelling itself is kept for the structural aliases, which this index does not hold. +fn fn_reach_target_keys(index: TypeSummaryIndex, target: String) -> List { + match map_get(index.by_key, target) { + Present { value: _ } => [target] + Absent => concat(type_summary_keys_of_leaf(index: index, leaf: target), [target]) + } +} + +fn fn_reach_holds_directly(name: String, summaries: TypeSummaryIndex, structural_alias_direct_fn_names: Set) -> Bool { + match map_get(summaries.by_key, name) { Present { value: s } => s.has_fn_fields Absent => set_contains(structural_alias_direct_fn_names, name) } } -fn fn_reach_targets(name: String, summaries: Map, structural_alias_fn_surface_names: Map>) -> List { - match map_get(summaries, name) { +fn fn_reach_targets(name: String, summaries: TypeSummaryIndex, structural_alias_fn_surface_names: Map>) -> List { + let spelled = match map_get(summaries.by_key, name) { Present { value: s } => concat(map_values(s.field_type_map), s.field_import_surface_names) Absent => match map_get(structural_alias_fn_surface_names, name) { @@ -821,9 +1072,10 @@ fn fn_reach_targets(name: String, summaries: Map, structura Absent => [] } } + spelled |> fold(init: [], f: (acc, t) => concat(acc, fn_reach_target_keys(index: summaries, target: t))) } -fn fn_reaching_names_fixpoint(candidates: List, summaries: Map, structural_alias_fn_surface_names: Map>, structural_alias_direct_fn_names: Set, reached: Set) -> Set { +fn fn_reaching_names_fixpoint(candidates: List, summaries: TypeSummaryIndex, structural_alias_fn_surface_names: Map>, structural_alias_direct_fn_names: Set, reached: Set) -> Set { let round = fold(candidates, init: FnReachRound { reached: reached, grew: false }, f: (acc, name) => if set_contains(acc.reached, name) { acc } else if fn_reach_holds_directly(name: name, summaries: summaries, structural_alias_direct_fn_names: structural_alias_direct_fn_names) @@ -837,9 +1089,9 @@ fn fn_reaching_names_fixpoint(candidates: List, summaries: Map, structural_alias_fn_surface_names: Map>, structural_alias_direct_fn_names: Set) -> Set { +fn fn_reaching_names(summaries: TypeSummaryIndex, structural_alias_fn_surface_names: Map>, structural_alias_direct_fn_names: Set) -> Set { fn_reaching_names_fixpoint( - candidates: concat(map_keys(summaries), map_keys(structural_alias_fn_surface_names)), + candidates: concat(map_keys(summaries.by_key), map_keys(structural_alias_fn_surface_names)), summaries: summaries, structural_alias_fn_surface_names: structural_alias_fn_surface_names, structural_alias_direct_fn_names: structural_alias_direct_fn_names, @@ -847,26 +1099,30 @@ fn fn_reaching_names(summaries: Map, structural_alias_fn_su ) } -fn close_fn_fields(summaries: Map, structural_alias_fn_surface_names: Map>, structural_alias_direct_fn_names: Set) -> Map { +fn close_fn_fields(summaries: TypeSummaryIndex, structural_alias_fn_surface_names: Map>, structural_alias_direct_fn_names: Set) -> TypeSummaryIndex { let reaching = fn_reaching_names(summaries: summaries, structural_alias_fn_surface_names: structural_alias_fn_surface_names, structural_alias_direct_fn_names: structural_alias_direct_fn_names) - fold(map_keys(summaries), init: summaries, f: (acc, name) => - match map_get(summaries, name) { - Present { value: s } => - if !s.has_fn_fields && set_contains(reaching, name) { - map_insert(acc, name, TypeSummary { - name: s.name, - repr: s.repr, - field_summaries: s.field_summaries, - field_type_map: s.field_type_map, - field_import_surface_names: s.field_import_surface_names, - variant_name_set: s.variant_name_set, - generic_param_names: s.generic_param_names, - has_fn_fields: true - }) - } else { acc } - Absent => acc - } - ) + TypeSummaryIndex { + by_key: fold(map_keys(summaries.by_key), init: summaries.by_key, f: (acc, key) => + match map_get(summaries.by_key, key) { + Present { value: s } => + if !s.has_fn_fields && set_contains(reaching, key) { + map_insert(acc, key, TypeSummary { + name: s.name, + key: s.key, + repr: s.repr, + field_summaries: s.field_summaries, + field_type_map: s.field_type_map, + field_import_surface_names: s.field_import_surface_names, + variant_name_set: s.variant_name_set, + generic_param_names: s.generic_param_names, + has_fn_fields: true + }) + } else { acc } + Absent => acc + } + ), + keys_by_leaf: summaries.keys_by_leaf + } } fn structural_alias_direct_fn_names_with(names: Set, name: String, include: Bool) -> Set { @@ -912,7 +1168,9 @@ fn add_emit_item_summary(state: EmitInfoBuildState, module_name: String, item: N state } match build_type_summary(item: item, source_indices: source_indices) { - Present { value: summary } => + Present { value: built } => + let key = type_decl_identity(owner_module: module_name, decl_name: built.name) + let summary = type_summary_with_key(summary: built, key: key) let with_variants = match summary.repr { EnumRepr { unit_only: _ } => fold(item.children, init: state.type_summaries, f: (acc, variant) => @@ -925,9 +1183,11 @@ fn add_emit_item_summary(state: EmitInfoBuildState, module_name: String, item: N ) let vname = authored_name_at(source_indices: source_indices, node: variant) let qualified_vname = variant_summary_key(enum_name: summary.name, variant_name: vname) + let variant_key = variant_summary_key(enum_name: key, variant_name: vname) let variant_field_types = build_field_type_map(children: variant.children, source_indices: source_indices) - map_insert(acc, qualified_vname, TypeSummary { + type_summary_index_insert(index: acc, key: variant_key, leaf: qualified_vname, summary: TypeSummary { name: qualified_vname, + key: variant_key, repr: StructRepr, field_summaries: build_struct_field_summaries(parent: variant, source_indices: source_indices), field_type_map: variant_field_types.field_types, @@ -940,7 +1200,7 @@ fn add_emit_item_summary(state: EmitInfoBuildState, module_name: String, item: N ) _ => state.type_summaries } - let next_summaries = map_insert(with_variants, summary.name, summary) + let next_summaries = type_summary_index_insert(index: with_variants, key: key, leaf: summary.name, summary: summary) EmitInfoBuildState { type_summaries: next_summaries, type_decl_items: state.type_decl_items, @@ -952,4 +1212,18 @@ fn add_emit_item_summary(state: EmitInfoBuildState, module_name: String, item: N } } +fn type_summary_with_key(summary: TypeSummary, key: String) -> TypeSummary { + TypeSummary { + name: summary.name, + key: key, + repr: summary.repr, + field_summaries: summary.field_summaries, + field_type_map: summary.field_type_map, + field_import_surface_names: summary.field_import_surface_names, + variant_name_set: summary.variant_name_set, + generic_param_names: summary.generic_param_names, + has_fn_fields: summary.has_fn_fields + } +} + data emit_dependency_registration_dissolve_on_note: DissolutionCondition = unbound_dissolution(description: "dissolve-on (FreeMonoid pass 2026-07-20): collect emitted cross-module type/path refs during emit into one authority; derive (a) use-lines via build_shared_types + reference_derived_use_line_plan and (b) closure pub-mod membership via emit_lib_rs_from_paths from that set. Instance-patch interim: closure projections (v1.compiler.closure_stub_v2_std_text_rust and closure_stub_v2_std_integer_rust) when refs exist but the real v2.std.text or v2.std.integer module is absent from narrow typed.modules — projections are NOT parallel modeling authorities (see each stub module dissolve_on_note); they dissolve when the ref set includes the real module in the closure.") diff --git a/src/v1/04_env.dag b/src/v1/04_env.dag index 2ea38c63c13..aae46928060 100644 --- a/src/v1/04_env.dag +++ b/src/v1/04_env.dag @@ -226,6 +226,8 @@ type SymbolIndex { services: Map transparent_alias_rep: Map type_head_exposures: Map + file_modules: Map + module_named_imports: Map> } type Scope { @@ -233,7 +235,7 @@ type Scope { } fn empty_symbol_index() -> SymbolIndex { - SymbolIndex { entries: empty_map(), global_bare: empty_map(), services: empty_map(), transparent_alias_rep: empty_map(), type_head_exposures: empty_map() } + SymbolIndex { entries: empty_map(), global_bare: empty_map(), services: empty_map(), transparent_alias_rep: empty_map(), type_head_exposures: empty_map(), file_modules: empty_map(), module_named_imports: empty_map() } } fn empty_type_env() -> TypeEnv { @@ -259,6 +261,97 @@ fn symbol_index_lookup(index: SymbolIndex, qualified_name: String) -> Node? { map_get(index.entries, qualified_name) } +// THE KERNEL NAMES NO IMPORT OVERRIDES: the resolver's scope layer for the kernel sits positionally +// above imports (v1.compiler.infer direct_import_export_precedence_note: locals > kernel > +// direct-selected > transitive). It lives here, beside the occurrence decision below, so the +// resolver's overlay and the emitter's unstamped-occurrence route read one predicate. +fn overlay_skips_kernel_name(name: String) -> Bool { + is_kernel_type(name: name) + || is_container_type(name: name) + || name == "Unit" + || name == "Optional" + || name == "Present" + || name == "Absent" +} + +// WHAT A BARE NAME DENOTES AT ONE UNSTAMPED OCCURRENCE, in the order the typechecker binds a +// declaration-field type: lookup_type_for reaches lookup_binding, which answers from the module's own +// env.bindings -- its declarations and the names it imports BY NAME -- before lookup_binding_by_name +// reaches the overlay where the kernel layer sits above imports (overlay_skips_kernel_name). So: a +// declaration in the occurrence's own file, then the file's named import, then the kernel. That the +// overlay's order (v1.compiler.infer direct_import_export_precedence_note) disagrees for an imported +// kernel-named declaration that has no mint row is the residual class +// (gunbc.recurring_failure_mode.an_imported_name_shadowed_by_a_kernel_name); this decision mirrors the +// binding the typechecker actually uses. It is the emitter's COPY of that order for references that +// arrive with no resolution fact -- type-environment declaration bodies whose members were never +// stamped -- and a counted route, not a second authority: v1.compiler.infer_emit_info +// resolve_type_decl_routed and v1.compiler.emit_rust is_host_optional_carrier_type read it, and it is +// deleted when those bodies carry Node.declaration stamped in the DECLARING scope +// (v1.compiler.infer_emit_info referencing_module_declarer_route_dissolves_on). +type BareOccurrenceBinding + = BareOccurrenceDeclaredInItsFile { declaration: Node } + | BareOccurrenceImportedByName { module_path: String, declaration: Node } + | BareOccurrenceIsKernelName + | BareOccurrenceUndecided + +fn symbol_index_bare_declarations(index: SymbolIndex, name: String) -> List { + match map_get(index.global_bare, name) { + Present { value: GlobalBareUniqueBinding { module_path: _, binding: b } } => [b.resolved] + Present { value: GlobalBareAmbiguousBinding { candidates: cs } } => cs |> map(c => c.binding.resolved) + Absent => [] + } +} + +// A NAMED IMPORT is followed the way lookup_binding follows it: a module that itself imports the name +// by name re-exports it (v2.std.collection imports std.optional { Optional }), so the chain is +// walked to the module that DECLARES the name. A chain that ends in a module holding no such +// declaration, or that does not end within the bound, is Undecided and refuses; it never falls +// through to the kernel. +fn bare_occurrence_import(index: SymbolIndex, name: String, reference: Node) -> BareOccurrenceBinding? { + match map_get(index.file_modules, reference.span.file) { + Absent => none + Present { value: referencing_module } => + match symbol_index_named_import_source(index: index, module_path: referencing_module, name: name) { + Absent => none + Present { value: from_module } => Present { value: bare_occurrence_import_terminal(index: index, module_path: from_module, name: name, fuel: 16) } + } + } +} + +fn symbol_index_named_import_source(index: SymbolIndex, module_path: String, name: String) -> String? { + match map_get(index.module_named_imports, module_path) { + Absent => none + Present { value: named } => map_get(named, name) + } +} + +fn bare_occurrence_import_terminal(index: SymbolIndex, module_path: String, name: String, fuel: Int) -> BareOccurrenceBinding { + if fuel == 0 { BareOccurrenceUndecided } + else { + match symbol_index_named_import_source(index: index, module_path: module_path, name: name) { + Present { value: next } => bare_occurrence_import_terminal(index: index, module_path: next, name: name, fuel: fuel - 1) + Absent => + match symbol_index_lookup(index: index, qualified_name: concat(module_path, ".", name)) { + Present { value: decl } => BareOccurrenceImportedByName { module_path: module_path, declaration: decl } + Absent => BareOccurrenceUndecided + } + } + } +} + +fn bare_occurrence_binding(index: SymbolIndex, name: String, reference: Node) -> BareOccurrenceBinding { + let local = symbol_index_bare_declarations(index: index, name: name) |> filter(d => d.span.file == reference.span.file) + let local_count = local |> fold(init: 0, f: (n, _d) => n + 1) + if local_count == 1 { local |> fold(init: BareOccurrenceUndecided, f: (acc, d) => BareOccurrenceDeclaredInItsFile { declaration: d }) } + else if local_count > 1 { BareOccurrenceUndecided } + else { + match bare_occurrence_import(index: index, name: name, reference: reference) { + Present { value: imported } => imported + Absent => if overlay_skips_kernel_name(name: name) { BareOccurrenceIsKernelName } else { BareOccurrenceUndecided } + } + } +} + fn global_bare_candidates_contain(candidates: List, resolved: Node) -> Bool { candidates |> any(c => c.binding.resolved == resolved) } @@ -298,7 +391,9 @@ fn symbol_index_insert(index: SymbolIndex, qualified_name: String, resolved: Nod global_bare: index.global_bare, services: index.services, transparent_alias_rep: index.transparent_alias_rep, - type_head_exposures: index.type_head_exposures + type_head_exposures: index.type_head_exposures, + file_modules: index.file_modules, + module_named_imports: index.module_named_imports } } @@ -308,7 +403,9 @@ fn symbol_index_insert_decl(index: SymbolIndex, module_path: String, binding: Ty global_bare: symbol_index_track_global_bare(global_bare: index.global_bare, module_path: module_path, binding: binding), services: index.services, transparent_alias_rep: index.transparent_alias_rep, - type_head_exposures: index.type_head_exposures + type_head_exposures: index.type_head_exposures, + file_modules: index.file_modules, + module_named_imports: index.module_named_imports } } @@ -318,7 +415,9 @@ fn symbol_index_insert_service(index: SymbolIndex, name: String, module_path: St global_bare: index.global_bare, services: map_insert(index.services, name, ServiceCensusEntry { module_path: module_path, item: item }), transparent_alias_rep: index.transparent_alias_rep, - type_head_exposures: index.type_head_exposures + type_head_exposures: index.type_head_exposures, + file_modules: index.file_modules, + module_named_imports: index.module_named_imports } } diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 0fc07cbcaeb..b68ca34396c 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -124,7 +124,7 @@ import v1.compiler.infer_method { } import v1.compiler.infer_cycle { detect_type_cycles_kahn } import v1.compiler.coercion { provenance_realizes_natively } -import v1.compiler.infer_env { +import v1.compiler.infer_env { overlay_skips_kernel_name, text_representation_by_identity, text_crossing_by_identity, host_text_into_structural_sequence, text_representations_cross, text_representation_is_text_arm, text_representation_is_unidentified, TypeEnv, TypeBinding, TypeEnvCache, empty_type_env_cache, merge_type_env_cache, merge_type_env_cache_guarded, GuardedTypeEnvCacheMerge, TypeEnvCacheMergeConflict, @@ -189,7 +189,7 @@ import v1.compiler.infer_sigs { } import v1.compiler.infer_emit_info { TypeRepr, StructRepr, EnumRepr, - TypeSummary, EmitGraphInfo, EmitInfoBuildState, + TypeSummary, EmitGraphInfo, EmitInfoBuildState, TypeSummaryIndex, TypeSummaryLookup, TypeSummaryFound, TypeSummaryLeafAmbiguous, TypeSummaryNotDeclared, TypeSummaryQuestion, QuestionDecided, QuestionNameAmbiguous, QuestionNotDeclared, type_summary_lookup, empty_type_summary_index, is_enum_in_summaries, empty_emit_graph_info, empty_type_env, lookup_emit_type_summary, build_struct_field_summaries, build_enum_field_summaries, add_emit_item_summary, derive_variant_to_enum, close_fn_fields, empty_type_decl_index, type_decl_index_with_qualified_names @@ -746,7 +746,7 @@ fn variant_reference_inferred_node(expected: Node?, name: String, owner_name: St // THE IDENTITY OF AN ARM WHOSE OWNER IS A KERNEL MINT. A mint that a // gunbc.structural_realization_bindings kernel_mint_declaration_rows row binds to a corpus -// declaration answers with THAT declaration (the kernel Optional is v2.std.optional Optional), so +// declaration answers with THAT declaration (the kernel Optional is std.optional Optional), so // the arm has one identity whether it was reached through `T?` or through an import. A mint with // no row is a kernel type or it is unrecovered, as before. fn kernel_mint_parent_identity(minted_name: String) -> VariantParentIdentity { @@ -7231,7 +7231,7 @@ fn validate_cast(source_inferred: InferredNode?, target_name: String, span: Sour // with the absence intact, so it is left to validate_cast. // // WAS `source_name == "Optional"`, and a BARE-SPELLING comparison is the defect: authored -// names reach here qualified as often as not, so a source typed `v2.std.optional.Optional` +// names reach here qualified as often as not, so a source typed `std.optional.Optional` // was not recognised as optional at all and its cast escaped OptionalCastNotEliminated // entirely. qualified_last_segment is the authority this file already uses for exactly this // question (nominal_call_arg_brand_mismatch, is_set_collection); asking it here is using the @@ -14970,6 +14970,15 @@ fn transparent_alias_identity_agrees(index: SymbolIndex, left: String, right: St } } +// A MODULE'S NAMED IMPORTS, leaf -> the module it is imported from, read from its import nodes: the +// import half of v1.compiler.infer_env bare_occurrence_binding. +fn file_named_imports_of(module_node: Node, source_indices: Map) -> Map { + module_imports(n: module_node) |> filter(imp => !import_is_all(n: imp)) |> fold(init: empty_map(), f: (acc, imp) => + let from_module = import_module_path_at(imp: imp, source_indices: source_indices) + import_specific_names_at(n: imp, source_indices: source_indices) |> fold(init: acc, f: (inner, name) => map_insert(inner, name, from_module)) + ) +} + fn build_symbol_index_census_raw_nodes(module_nodes: List, source_indices: Map) -> SymbolIndex { let corpus_variant_counts = corpus_disj_variant_name_counts_nodes(module_nodes: module_nodes, source_indices: source_indices) let corpus_item_counts = corpus_item_name_counts_nodes(module_nodes: module_nodes, source_indices: source_indices) @@ -14999,7 +15008,11 @@ fn build_symbol_index_census_raw_nodes(module_nodes: List, source_indices: services: folded.services, transparent_alias_rep: transparent_alias_representatives( module_nodes: module_nodes, source_indices: source_indices, item_counts: corpus_item_counts), - type_head_exposures: type_head_exposure_census(module_nodes: module_nodes, source_indices: source_indices) + type_head_exposures: type_head_exposure_census(module_nodes: module_nodes, source_indices: source_indices), + file_modules: module_nodes |> fold(init: empty_map(), f: (acc, module_node) => + map_insert(acc, module_node.span.file, authored_name_at(source_indices: source_indices, node: module_node))), + module_named_imports: module_nodes |> fold(init: empty_map(), f: (acc, module_node) => + map_insert(acc, authored_name_at(source_indices: source_indices, node: module_node), file_named_imports_of(module_node: module_node, source_indices: source_indices))) } } @@ -15209,7 +15222,7 @@ fn census_bare_fill_with_resolved_fn_sigs(index: SymbolIndex, source_indices: Ma Absent => acc } ) - SymbolIndex { entries: index.entries, global_bare: global2, services: services2, transparent_alias_rep: index.transparent_alias_rep, type_head_exposures: index.type_head_exposures } + SymbolIndex { entries: index.entries, global_bare: global2, services: services2, transparent_alias_rep: index.transparent_alias_rep, type_head_exposures: index.type_head_exposures, file_modules: index.file_modules, module_named_imports: index.module_named_imports } } fn census_with_resolved_fn_sigs(index: SymbolIndex, source_indices: Map) -> SymbolIndex { @@ -15228,7 +15241,7 @@ fn census_with_resolved_fn_sigs(index: SymbolIndex, source_indices: Map, source_indices: Map) -> SymbolIndex { @@ -15268,7 +15281,9 @@ fn symbol_index_with_bare_fill(closure: SymbolIndex, tree: SymbolIndex) -> Symbo SymbolIndex { entries: closure.entries, global_bare: global2, services: services2, transparent_alias_rep: map_merge(tree.transparent_alias_rep, closure.transparent_alias_rep), - type_head_exposures: map_merge(tree.type_head_exposures, closure.type_head_exposures) + type_head_exposures: map_merge(tree.type_head_exposures, closure.type_head_exposures), + file_modules: map_merge(tree.file_modules, closure.file_modules), + module_named_imports: map_merge(tree.module_named_imports, closure.module_named_imports) } } @@ -15307,20 +15322,14 @@ fn symbol_index_with_qualified_fill(closure: SymbolIndex, fill: SymbolIndex) -> SymbolIndex { entries: entries2, global_bare: closure.global_bare, services: closure.services, transparent_alias_rep: map_merge(fill.transparent_alias_rep, closure.transparent_alias_rep), - type_head_exposures: map_merge(fill.type_head_exposures, closure.type_head_exposures) + type_head_exposures: map_merge(fill.type_head_exposures, closure.type_head_exposures), + file_modules: map_merge(fill.file_modules, closure.file_modules), + module_named_imports: map_merge(fill.module_named_imports, closure.module_named_imports) } } data direct_import_export_precedence_note: String = "Direct-selected exports beat transitive leaks (2026-07-16, the #6663 x #6686 main-red). The ancestry union folds each direct import's WHOLE flattened cache (its own exports AND everything it inherited), so a later import's transitively-leaked homonym could overlay an earlier import's OWN export that this module's import statement explicitly selects - import v2.std.algebra { Monoid } lost 'Monoid' to dag-root std.algebra riding v2.std.node's ancestry via std.types, and #6663's field-presence wall read the wrong shape at 28 sites. This overlay re-applies, in import order, each direct import's OWN export surface (interface.env.str_bindings - locals only, never its ancestry) restricted to the names the import statement makes visible (specific_names; is_all = the parent's whole local surface, type-variable names filtered per the std.types precedent). Winner semantics: direct-selected vs transitive leak = direct wins (lexical nearest-wins, the containment ruling one hop out - the sanctioned 1c universe is own declarations UNION direct import lists); direct vs direct = unchanged import-order overlay-wins (the ledgered peer-fork ruling, 2026-07-11: later import wins, conflict stays LEDGERED on binding_forks); leak vs leak = unchanged union winner; KERNEL names are never overridden (overlay_skips_kernel_name: kernel_type_set, the container_type_arity names List/Set/Map/Witness, plus Unit/Optional/Present/Absent) - the kernel scope layer stays positionally above imports per the same ruling, because builtin typing (first, skip, string ops) grounds on kernel identities and the v2 substrate models of those concepts (v2.std.collection List=FreeMonoid, Optional; v2.std.text String) are the known dual-representation debt, resolved corpus-wide by kernel-wins today. KERNEL INSTALLATION IS INDEPENDENT OF IMPORT CARDINALITY (build_ancestry_precedence, 2026-08-31): the kernel overlay applies unconditionally over the import union and both type-env builders consume the one producer - the former shape skipped the overlay when a module had exactly one import, so kernel identity won or lost by ancestry occupancy (a leak-dependent regime: identical imports, different realizations). Full precedence, nearest first: locals > kernel > direct-selected > transitive union. The fork LEDGER is untouched - rows still record every union conflict; this layer only corrects which binding serves lookups. DISSOLVES WHEN namespace Rule-1 lands (containment tree is the naming authority; imports become parse errors) - the union leak itself disappears and this overlay with it. Receipt: direct_import_precedence_over_transitive_leak_test (green arm = selected name resolves the selected module's shape regardless of import order; red control = the field wall still refuses the true shape's missing fields, with that arm's modules placed so the homonym is census-UNAMBIGUOUS by containment (realleaf under the consumer's own parent, leakleaf under a sibling parent) - a census-ambiguous name stands the wall down BY DESIGN (presence_check_census_gate_note), so without that placement the control asserts a diagnostic the gate exists to suppress and silently measures the gate instead of the overlay; ledger arm = the fork row is still recorded)." -fn overlay_skips_kernel_name(name: String) -> Bool { - is_kernel_type(name: name) - || is_container_type(name: name) - || name == "Unit" - || name == "Optional" - || name == "Present" - || name == "Absent" -} fn overlay_direct_import_exports(ancestry_str_bindings: Map, resolved_imports: List, parent_index: Map) -> Map { fold(resolved_imports, init: ancestry_str_bindings, f: (acc, imp) => @@ -15384,7 +15393,7 @@ fn build_ancestry_precedence(resolved_imports: List, parent_inde // THE SEED'S ONE MINT OF THE OPTIONAL COPRODUCT. `T?` resolves to this node in every kernel scope // this module builds; it was written out three times, once per builder. It is a mint and not the -// declaration: a module that uses `T?` need not hold v2.std.optional in its closure. Which +// declaration: a module that uses `T?` need not hold std.optional in its closure. Which // declaration it stands for is gunbc.structural_realization_bindings kernel_mint_declaration_rows, // and kernel_mint_shape_diagnostics refuses if the two stop agreeing. fn kernel_optional_type_node() -> Node { @@ -17326,16 +17335,12 @@ type EnumVariantShapeSets { positional_payload: Set } -fn enum_variant_shape_sets_for_item(acc: EnumVariantShapeSets, item: Node, si: Map, type_summaries: Map) -> EnumVariantShapeSets { +fn enum_variant_shape_sets_for_item(acc: EnumVariantShapeSets, item: Node, si: Map, type_summaries: TypeSummaryIndex) -> EnumVariantShapeSets { let item_name = authored_name_at(source_indices: si, node: item) - let is_enum = match map_get(type_summaries, item_name) { - Present { value: summary } => match summary.repr { - EnumRepr { unit_only: _ } => true - _ => false - } - Absent => false - } - if is_enum { + if match is_enum_in_summaries(type_summaries: type_summaries, type_name: item_name) { + QuestionDecided { value: v } => v + _ => false + } { item.children |> fold(init: acc, f: (vacc, variant) => let qualified = concat(item_name, "::", authored_name_at(source_indices: si, node: variant)) let is_positional_payload = variant_has_positional_payload_shape(variant: variant, source_indices: si) @@ -17351,7 +17356,7 @@ fn enum_variant_shape_sets_for_item(acc: EnumVariantShapeSets, item: Node, si: M } else { acc } } -fn build_enum_variant_shape_sets(modules: List, type_summaries: Map) -> EnumVariantShapeSets { +fn build_enum_variant_shape_sets(modules: List, type_summaries: TypeSummaryIndex) -> EnumVariantShapeSets { modules |> fold(init: EnumVariantShapeSets { fielded: empty_set(), positional_payload: empty_set() }, f: (acc, m) => m.items |> fold(init: acc, f: (inner, item) => enum_variant_shape_sets_for_item(acc: inner, item: item, si: m.type_env.source_indices, type_summaries: type_summaries) @@ -17435,7 +17440,7 @@ fn build_emit_graph_info(modules: List, registry: Map empty_symbol_index() } let init = EmitInfoBuildState { - type_summaries: empty_map(), + type_summaries: empty_type_summary_index(), type_decl_items: type_decl_index_with_qualified_names(index: empty_type_decl_index(), qualified_names: qualified_names), fn_decl_items: empty_map(), structural_alias_fn_surface_names: empty_map(), diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 87ac7976dcf..2c3d936601b 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -184,7 +184,7 @@ import std.types { is_container_type, is_kernel_type, container_template_algebra import std.serialization { CoproductWireContract, VariantEncoding, VariantNaming } import v1.compiler.infer_env { lookup_unit_variant_phantom_type, UnitVariantPhantomPresent, UnitVariantPhantomAbsent, UnitVariantPhantomEvidenceUnavailable, - TypeEnv, TypeBinding, authored_name, lookup_type_by_name, lookup_binding_by_name, lookup_type_for, GlobalBareLookupState, GlobalBareUniqueBinding, GlobalBareAmbiguousBinding, empty_symbol_index, binding_declares_span, type_reference_declaration_ref } + TypeEnv, TypeBinding, authored_name, lookup_type_by_name, lookup_binding_by_name, lookup_type_for, GlobalBareLookupState, GlobalBareUniqueBinding, GlobalBareAmbiguousBinding, empty_symbol_index, empty_type_env, declaration_ref_of_declaration_node, bare_occurrence_binding, BareOccurrenceBinding, BareOccurrenceDeclaredInItsFile, BareOccurrenceImportedByName, BareOccurrenceIsKernelName, BareOccurrenceUndecided, binding_declares_span, type_reference_declaration_ref } import std.operator_realization { OperatorRealization, HostOperator, StructuralEquality, StructuralComparison, OperatorRealizationRefused, OperandRealization, HostNumericOperand, StructuralOperand, OperandIdentityUnavailable, @@ -196,7 +196,7 @@ import std.operator_realization { } import gunbc.structural_realization_bindings { structural_ordering_rows, kernel_grounding_rows, kernel_mint_declaration_rows, kernel_optional_mint_name } import gunbc.rust_source_type_bindings { rust_host_option_carrier_declarations } -import std.literal_elaboration { KernelIntLiteral, kernel_grounding_for, KernelGroundingFound, KernelGroundingAbsent, KernelGroundingAmbiguous, kernel_mint_ownership, DeclarationOwnsTheMint, DeclarationDoesNotOwnTheMint, KernelMintOwnershipAmbiguous } +import std.literal_elaboration { KernelIntLiteral, kernel_grounding_for, KernelGroundingFound, KernelGroundingAbsent, KernelGroundingAmbiguous, kernel_mint_ownership, DeclarationOwnsTheMint, DeclarationDoesNotOwnTheMint, KernelMintOwnershipAmbiguous, kernel_mint_declaration_for, KernelMintDeclarationFound, KernelMintDeclarationAbsent, KernelMintDeclarationAmbiguous } import v1.compiler.infer_types { resolved_type, normalize_access_type_node, for_each_element_type_node, child_type_node, emit_map_has, @@ -231,9 +231,9 @@ import v1.compiler.infer { caller_resource_requirements, established_resource_binding } import v1.compiler.infer_emit_info { - EmitGraphInfo, TypeSummary, StructRepr, EnumRepr, + EmitGraphInfo, TypeSummary, StructRepr, EnumRepr, TypeSummaryIndex, TypeSummaryLookup, TypeSummaryFound, TypeSummaryLeafAmbiguous, TypeSummaryNotDeclared, TypeSummaryQuestion, QuestionDecided, QuestionNameAmbiguous, QuestionNotDeclared, type_summary_lookup, type_summary_values, type_summary_of_reference, type_summary_answer, type_summary_decided, summary_is_enum_with_variant, type_summary_keys_of_leaf, lookup_emit_type_summary, empty_emit_graph_info, - TypeDeclIndex, type_decl_identity, + TypeDeclIndex, type_decl_identity, type_decl_identities_of_leaf, TypeDeclResolved, TypeDeclLeafAmbiguous, TypeDeclKernelSpellingUndecided, TypeDeclNotDeclared, resolve_type_decl_reference, emit_info_with_fn_type_context, emit_info_with_fn_return, emit_info_with_expected_type, is_enum_in_summaries, find_variant_parent, is_known_variant, @@ -300,7 +300,7 @@ fn render_rust_applied_via_emit_info(n: Node, shared_types: Set, source_ fn render_rust_type(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } - if is_host_optional_carrier_type(n: n, source_indices: source_indices) { + if is_host_optional_carrier_type(n: n, source_indices: source_indices, env: emit_info.fn_type_env) { return render_rust_optional_carrier_applied(n: n, generic_param_names: emit_info.fn_generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: emit_info.variant_to_enum, env: emit_info.fn_type_env) } if is_host_diagnostics_carrier_type(n: n, source_indices: source_indices) { @@ -395,7 +395,7 @@ fn render_rust_arrow_type_in_scope(n: Node, generic_param_names: List, s // documented unresolved-reference shape), so every identity-keyed arm ahead of this one answers // about the wrong declaration. Rendering the bare name can only bind where the emitted module // declares or imports that name, and for the String spelling neither holds: kernel names are never -// overridden by imports (#9813, v1.compiler.infer overlay_skips_kernel_name), so the use-line that +// overridden by imports (#9813, v1.compiler.infer_env overlay_skips_kernel_name), so the use-line that // would bind the alias is dropped by import_name_resolves_to_host_realized_kernel_scalar and the // bare token binds the prelude String -- while every value position renders the same carrier // Rc>. That is the v2_compiler_tokenize.rs E0308 family on the XL-N board (41 of 72), @@ -430,7 +430,7 @@ fn rust_overlayless_alias_leaf_requires_peel(env: TypeEnv, n: Node) -> Bool { fn render_rust_type_without_applied_binding(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } - if is_host_optional_carrier_type(n: n, source_indices: source_indices) { + if is_host_optional_carrier_type(n: n, source_indices: source_indices, env: emit_info.fn_type_env) { return render_rust_optional_carrier_applied(n: n, generic_param_names: emit_info.fn_generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: emit_info.variant_to_enum, env: emit_info.fn_type_env) } if is_host_diagnostics_carrier_type(n: n, source_indices: source_indices) { @@ -544,10 +544,6 @@ fn is_host_freemonoid_vec_alias(name: String) -> Bool { name == "FreeMonoid" } -fn is_host_optional_carrier_alias(name: String) -> Bool { - name == kernel_optional_mint_name -} - // THE NAME PROJECTION OF ONE ROW, not a second table. Which declarations the Rust target realizes // as its host option is gunbc.rust_source_type_bindings rust_host_option_carrier_declarations; the // sites that still hold only a type's NAME (type rendering, and pattern arms inference did not @@ -558,12 +554,39 @@ fn is_host_diagnostics_carrier_alias(name: String) -> Bool { rust_host_option_carrier_declarations |> any(d => (d.decl_name as String) == name) } -fn is_grounded_coproduct_native_alias(name: String) -> Bool { - is_host_freemonoid_vec_alias(name: name) - || is_host_optional_carrier_alias(name: name) - || is_host_diagnostics_carrier_alias(name: name) +// WHETHER A DECLARATION IS REALIZED AS A HOST CARRIER (Vec for FreeMonoid, Option for the kernel +// optional and the diagnostics carrier) is a fact about the declaration: whether this declaration is realized as a host carrier is a fact about it, so a coproduct +// a module declares as `Optional` is not the host option (declaration_owns_host_option). +fn declaration_is_grounded_coproduct_native_alias(module_path: String, decl_name: String) -> Bool { + if contains(decl_name, ".") { + let segments = decl_name |> split(delimiter: ".") + declaration_is_grounded_coproduct_native_alias(module_path: segments |> take((segments |> count) - 1) |> join(separator: "."), decl_name: qualified_last_segment(name: decl_name)) + } else { + is_host_freemonoid_vec_alias(name: decl_name) + || declaration_owns_host_option(module_path: module_path, decl_name: decl_name) + || declaration_ref_in_list(target: decl_ref(module_path: module_path, decl_name: decl_name), refs: rust_host_option_carrier_declarations) + } +} + +// A parent named only by its leaf, reached through a module that may re-export rather than declare +// it: it is a host carrier when every declaration of that leaf in the closure is one. Nothing is +// chosen, so nothing is guessed; where declarations disagree the reader keeps its own declaring-module +// check. +fn every_declarer_is_grounded_coproduct_native_alias(decls: TypeDeclIndex, name: String) -> Bool { + let identities = type_decl_identities_of_leaf(index: decls, leaf: qualified_last_segment(name: name)) + (identities |> count) > 0 && identities |> all(identity => + declaration_is_grounded_coproduct_native_alias(module_path: "", decl_name: identity) + ) } +// A TypeSummary key is `.`: the identity type_decl_identity minted for it. +fn summary_declares_grounded_coproduct_native_alias(summary: TypeSummary) -> Bool { + let segments = summary.key |> split(delimiter: ".") + let module_path = segments |> take((segments |> count) - 1) |> join(separator: ".") + declaration_is_grounded_coproduct_native_alias(module_path: module_path, decl_name: summary.name) +} + + // A COPRODUCT THE CORPUS BINDS NATIVELY (gunbc.rust_source_type_bindings, keyed on the declaration) // REALIZES ONLY AS ITS HOST SPELLING: no enum is emitted for it, so there is no enum to glob-import // and no bridge to convert from. Its arms reach the target as the carrier's values @@ -579,8 +602,69 @@ fn rust_declaration_realizes_as_native_alias(module_path: String, decl_name: Str } } -fn is_host_optional_carrier_type(n: Node, source_indices: Map) -> Bool { - authored_name_at(source_indices: source_indices, node: n) == "Optional" && n.children |> count > 0 +// WHICH DECLARATION IS THE HOST OPTION is a fact about the declaration, read from the one row that +// binds it: the declaration the kernel optional mint stands for +// (gunbc.structural_realization_bindings kernel_mint_declaration_rows), the same reading +// host_option_arm_reading makes for a pattern arm. A declaration that is not that one is not the host +// option, whatever it is named: a coproduct a module declares as `Optional` emits as its own enum. +// Two rows binding the kernel optional decide no declaration, and none is answered as the host +// option here (the pattern side refuses that state, HostOptionArmBindingAmbiguous). +fn declaration_owns_host_option(module_path: String, decl_name: String) -> Bool { + match kernel_mint_ownership(rows: kernel_mint_declaration_rows, minted_name: kernel_optional_mint_name, declaration: decl_ref(module_path: module_path, decl_name: decl_name)) { + DeclarationOwnsTheMint => true + DeclarationDoesNotOwnTheMint => false + KernelMintOwnershipAmbiguous { row_count: _ } => false + } +} + +// A type reference that carries the declaration it names is decided by that declaration. A reference +// resolved to a declaration's STRUCTURE (lookup_type_for hands the emitter the declaration node itself, +// unstamped) is decided by WHICH declaration it is, read through the join every emitter reader of a +// declaration node uses (v1.compiler.infer_env declaration_ref_of_declaration_node: the declaring span +// against the corpus symbol index), so a coproduct another module declares as `Optional` is never read +// as the host option. A reference that is neither is decided by unstamped_reference_is_host_option. +// AN UNSTAMPED REFERENCE is decided by the one occurrence decision the type-declaration router reads +// (v1.compiler.infer_env bare_occurrence_binding: own file, then named import, then kernel -- the +// typechecker's lookup_binding order): the declaration that arm names, or on the kernel arm the +// declaration the kernel mint names. No leaf comparison stands in for any of them. +fn unstamped_reference_is_host_option(n: Node, source_indices: Map, env: TypeEnv) -> Bool { + let leaf = authored_name_at(source_indices: source_indices, node: n) + match bare_occurrence_binding(index: env.symbol_index, name: leaf, reference: n) { + BareOccurrenceDeclaredInItsFile { declaration: decl } => declaration_node_owns_host_option(decl: decl, source_indices: source_indices, env: env) + BareOccurrenceImportedByName { module_path: from_module, declaration: decl } => + declaration_owns_host_option(module_path: from_module, decl_name: leaf) || declaration_node_owns_host_option(decl: decl, source_indices: source_indices, env: env) + BareOccurrenceIsKernelName => + match kernel_mint_declaration_for(rows: kernel_mint_declaration_rows, minted_name: leaf) { + KernelMintDeclarationFound { declaration: d } => declaration_owns_host_option(module_path: d.module_path as String, decl_name: d.decl_name as String) + KernelMintDeclarationAbsent => false + KernelMintDeclarationAmbiguous { row_count: _ } => false + } + BareOccurrenceUndecided => false + } +} + +fn declaration_node_owns_host_option(decl: Node, source_indices: Map, env: TypeEnv) -> Bool { + match declaration_ref_of_declaration_node(decl: decl, source_indices: source_indices, env: env) { + Present { value: d } => declaration_owns_host_option(module_path: d.module_path as String, decl_name: d.decl_name as String) + Absent => false + } +} + +fn is_host_optional_carrier_type(n: Node, source_indices: Map, env: TypeEnv) -> Bool { + match n.declaration { + Present { value: d } => + match d.field { + WholeDeclaration => declaration_owns_host_option(module_path: d.module_path as String, decl_name: d.decl_name as String) + _ => false + } + Absent => + let is_declaration_structure = (n.module_item_kind == ModuleItemTypeDeclaration || n.connective == Disj) && n.ident_span != none + let declared = if is_declaration_structure { declaration_ref_of_declaration_node(decl: n, source_indices: source_indices, env: env) } else { none } + match declared { + Present { value: d } => declaration_owns_host_option(module_path: d.module_path as String, decl_name: d.decl_name as String) + Absent => unstamped_reference_is_host_option(n: n, source_indices: source_indices, env: env) + } + } } fn is_host_diagnostics_carrier_type(n: Node, source_indices: Map) -> Bool { @@ -1453,7 +1537,7 @@ fn render_rust_applied_type_arg(n: Node, generic_param_names: List, shar fn render_rust_applied_type(n: Node, generic_param_names: List, shared_types: Set, source_indices: Map, variant_to_enum: Map, env: TypeEnv) -> String { if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } - if is_host_optional_carrier_type(n: n, source_indices: source_indices) { + if is_host_optional_carrier_type(n: n, source_indices: source_indices, env: env) { return render_rust_optional_carrier_applied(n: n, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: variant_to_enum, env: env) } if is_host_diagnostics_carrier_type(n: n, source_indices: source_indices) { @@ -1644,7 +1728,7 @@ fn render_rust_decl_type(n: Node, generic_param_names: List, shared_type return render_rust_arrow_type_in_scope(n: n, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: variant_to_enum, env: env) } if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } - if is_host_optional_carrier_type(n: n, source_indices: source_indices) { + if is_host_optional_carrier_type(n: n, source_indices: source_indices, env: env) { return render_rust_optional_carrier_applied(n: n, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: variant_to_enum, env: env) } if is_host_diagnostics_carrier_type(n: n, source_indices: source_indices) { @@ -1766,7 +1850,7 @@ fn rust_carrier_optional_wrap(n: Node, rendered: String) -> String { fn render_rust_fn_sig_type(n: Node, generic_param_names: List, shared_types: Set, source_indices: Map, variant_to_enum: Map, env: TypeEnv) -> String { if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } - if is_host_optional_carrier_type(n: n, source_indices: source_indices) { + if is_host_optional_carrier_type(n: n, source_indices: source_indices, env: env) { return render_rust_optional_carrier_applied(n: n, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: variant_to_enum, env: env) } if is_host_diagnostics_carrier_type(n: n, source_indices: source_indices) { @@ -3138,7 +3222,7 @@ fn emit_rust_init_block_stmts(remaining: List, text: List, fn rust_qualify_type_leaf_name(name: String, variant_to_enum: Map) -> String { match map_get(variant_to_enum, name) { Present { value: parent } => - if parent != "" { rust_variant_path(parent: parent, rust_name: name) } else { name } + if parent != "" { rust_variant_path(parent: qualified_last_segment(name: parent), rust_name: name) } else { name } Absent => name } } @@ -3246,7 +3330,7 @@ fn maybe_mark_shared_type(acc: Set, summary: TypeSummary, recursive_type StructRepr => true EnumRepr { unit_only: unit_only } => unit_only == false } - if is_grounded_coproduct_native_alias(name: summary.name) { + if summary_declares_grounded_coproduct_native_alias(summary: summary) { acc } else if needs_sharing && !is_type_constant(summary: summary, recursive_type_set: recursive_type_set) { set_insert(acc, summary.name) @@ -3255,11 +3339,30 @@ fn maybe_mark_shared_type(acc: Set, summary: TypeSummary, recursive_type } } -fn build_shared_types(type_summaries: Map, recursive_type_set: Set, target: RenderTarget) -> Set { +// THE SHARED SET IS KEYED BY SPELLING, and the declaration and every use of a type read it by that +// spelling, so what keeps an emission consistent is that one spelling has one answer. A spelling two +// declarations own is shared only when EVERY declaration of it would be: a coproduct a module +// declares as `Optional` beside the host option (which is never shared) is then unshared at its +// declaration and at every use alike, and the host Option is not wrapped because a same-leaf type +// elsewhere needs sharing. The set is one of the indexes +// gunbc.recurring_failure_mode emitter_index_keyed_on_a_type_leaf_takes_the_last_declarer still +// names as leaf-keyed; this rule is what makes its leaf answer independent of fold order. +fn shared_by_every_declarer(type_summaries: TypeSummaryIndex, name: String, recursive_type_set: Set, target_needs_sharing: Bool) -> Bool { + type_summary_keys_of_leaf(index: type_summaries, leaf: name) |> all(key => + match type_summary_decided(index: type_summaries, key: key) { + Present { value: summary } => set_contains(maybe_mark_shared_type(acc: empty_set(), summary: summary, recursive_type_set: recursive_type_set, target_needs_sharing: target_needs_sharing), name) + Absent => true + } + ) +} + +fn build_shared_types(type_summaries: TypeSummaryIndex, recursive_type_set: Set, target: RenderTarget) -> Set { let sharing = sharing_for_target(target: target) - let user_shared = map_values(type_summaries) |> fold(init: empty_set(), f: (acc, summary) => - maybe_mark_shared_type(acc: acc, summary: summary, recursive_type_set: recursive_type_set, target_needs_sharing: sharing.needs_sharing) + let user_shared = type_summary_values(index: type_summaries) |> fold(init: empty_set(), f: (acc, summary) => + if shared_by_every_declarer(type_summaries: type_summaries, name: summary.name, recursive_type_set: recursive_type_set, target_needs_sharing: sharing.needs_sharing) { + maybe_mark_shared_type(acc: acc, summary: summary, recursive_type_set: recursive_type_set, target_needs_sharing: sharing.needs_sharing) + } else { acc } ) let collection_keys = sorted_map_keys(rust_container_templates) @@ -4159,7 +4262,7 @@ fn emit_inferred_type_leaf_name(n: Node, source_indices: Map, type_summaries: Map) -> String { +fn anonymous_record_lit_surface_name(n: Node, source_indices: Map, type_summaries: TypeSummaryIndex) -> String { let lit_field_names = n.children |> map(f => field_init_node_name_at(n: f, source_indices: source_indices)) let field_type_hints = fold(n.children, init: empty_map(), f: (acc, f) => let fname = field_init_node_name_at(n: f, source_indices: source_indices) @@ -4178,12 +4281,12 @@ fn anonymous_record_lit_surface_name(n: Node, source_indices: Map let rt = resolved_type(n: n) let rt_name = authored_name_at(source_indices: source_indices, node: rt) - if rt.ident_span != none && map_contains_key(type_summaries, rt_name) { rt_name } else { "" } + if rt.ident_span != none && (type_summary_decided(index: type_summaries, key: rt_name) != none) { rt_name } else { "" } } } } -fn record_lit_variant_payload_struct_surfaces(n: Node, source_indices: Map, type_summaries: Map, variant_to_enum: Map) -> List { +fn record_lit_variant_payload_struct_surfaces(n: Node, source_indices: Map, type_summaries: TypeSummaryIndex, variant_to_enum: Map) -> List { let variant_name = match record_lit_type_name_at(texpr: n, source_indices: source_indices) { Present { value: v } => v Absent => authored_name_at(source_indices: source_indices, node: n) @@ -4194,10 +4297,10 @@ fn record_lit_variant_payload_struct_surfaces(n: Node, source_indices: Map "" } if enum_name == "" { [] } else { - match map_get(type_summaries, variant_summary_key(enum_name: enum_name, variant_name: variant_name)) { + match type_summary_decided(index: type_summaries, key: variant_summary_key(enum_name: enum_name, variant_name: variant_name)) { Present { value: summary } => map_values(summary.field_type_map) |> filter(ft => - ft != "" && match map_get(type_summaries, ft) { + ft != "" && match type_summary_decided(index: type_summaries, key: ft) { Present { value: fts } => match fts.repr { StructRepr => true @@ -4224,7 +4327,7 @@ fn record_lit_field_type_hints(n: Node, source_indices: Map, source_indices: Map) -> List { +fn record_lit_resolved_ctor_import_names(type_name: String, n: Node, type_summaries: TypeSummaryIndex, source_indices: Map) -> List { let from_template = match container_template_algebra(name: type_name) { Present { value: algebra } => if algebra != "" && algebra != type_name { [algebra] } else { [] } Absent => [] @@ -4244,7 +4347,7 @@ fn record_lit_resolved_ctor_import_names(type_name: String, n: Node, type_summar unique_strings(items: concat(from_template, from_fields)) } -fn record_lit_ref_names(n: Node, source_indices: Map, type_summaries: Map, variant_to_enum: Map) -> List { +fn record_lit_ref_names(n: Node, source_indices: Map, type_summaries: TypeSummaryIndex, variant_to_enum: Map) -> List { match n.expr_data { ExprRecordLit { parent_enum: pe } => let tn_list = match record_lit_type_name_at(texpr: n, source_indices: source_indices) { @@ -4286,14 +4389,14 @@ fn record_lit_ref_names(n: Node, source_indices: Map, type // the text gate declares (P2a candidate-producer / BoundReferenceProvider deriving use-lines from // bound-reference structure). -fn collect_anonymous_record_lit_heads(n: Node, source_indices: Map, type_summaries: Map) -> List { +fn collect_anonymous_record_lit_heads(n: Node, source_indices: Map, type_summaries: TypeSummaryIndex) -> List { let self_head = match n.expr_data { ExprRecordLit { parent_enum: _ } => match record_lit_type_name_at(texpr: n, source_indices: source_indices) { Present { value: _ } => [] Absent => let inferred = emit_inferred_type_leaf_name(n: n, source_indices: source_indices) - if inferred != "" && map_contains_key(type_summaries, inferred) { [inferred] } else { + if inferred != "" && (type_summary_decided(index: type_summaries, key: inferred) != none) { [inferred] } else { let anon = anonymous_record_lit_surface_name(n: n, source_indices: source_indices, type_summaries: type_summaries) if anon != "" { [anon] } else { [] } } @@ -4335,13 +4438,13 @@ fn collect_items_field_import_surface_names(surface_names: List, emit_in let variant_to_enum = emit_info.variant_to_enum unique_strings(items: surface_names |> flat_map(type_name => - let summary_lookup = match map_get(type_summaries, type_name) { + let summary_lookup = match type_summary_decided(index: type_summaries, key: type_name) { Present { value: summary } => Present { value: summary } Absent => match map_get(variant_to_enum, type_name) { Present { value: enum_name } => if enum_name == "" { none } else { - map_get(type_summaries, variant_summary_key(enum_name: enum_name, variant_name: type_name)) + type_summary_decided(index: type_summaries, key: variant_summary_key(enum_name: enum_name, variant_name: type_name)) } Absent => none } @@ -4349,7 +4452,7 @@ fn collect_items_field_import_surface_names(surface_names: List, emit_in match summary_lookup { Present { value: summary } => summary.field_import_surface_names |> filter(field_type => - field_type != "" && match map_get(type_summaries, field_type) { + field_type != "" && match type_summary_decided(index: type_summaries, key: field_type) { Present { value: ft } => match ft.repr { StructRepr => true @@ -4370,7 +4473,7 @@ fn collect_items_field_import_surface_names(surface_names: List, emit_in // scrutinee type available at collection time the parent is resolved only when // unique_variant_parent finds exactly one owner, so a homonym variant proposes nothing rather // than guessing an enum (the candidate set may under-propose; it must never fabricate). -fn collect_pattern_ref_names(pattern: MatchPattern, type_summaries: Map) -> List { +fn collect_pattern_ref_names(pattern: MatchPattern, type_summaries: TypeSummaryIndex) -> List { match pattern { VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: _ } => let own = match pattern_parent_enum(name: qualified_last_segment(name: n), parent_enum: parent_enum, scrut_type: "", type_summaries: type_summaries) { @@ -4382,7 +4485,7 @@ fn collect_pattern_ref_names(pattern: MatchPattern, type_summaries: Map, type_summaries: Map, variant_to_enum: Map) -> List { +fn collect_value_ref_names(n: Node, source_indices: Map, type_summaries: TypeSummaryIndex, variant_to_enum: Map) -> List { let self_name = match n.expr_data { ExprVar { binding_kind: bk } => match bk { @@ -4459,7 +4562,7 @@ fn emit_scrutinee_type_name(scrutinee: Node, source_indices: Map) -> List { +fn collect_pattern_rc_prelude_parent_enums(pattern: MatchPattern, scrut_type: String, type_summaries: TypeSummaryIndex) -> List { match pattern { VariantPattern { name: n, parent_enum: parent_enum, field_bindings: _, parent_identity: _ } => let bare_n = qualified_last_segment(name: n) @@ -4544,7 +4647,7 @@ fn variant_record_lit_summary_key(n: Node, source_indices: Map, type_summaries: Map, variant_to_enum: Map) -> List { +fn collect_record_lit_field_struct_surfaces(parent: Node, field_init: Node, source_indices: Map, type_summaries: TypeSummaryIndex, variant_to_enum: Map) -> List { let field_name = field_init_node_name_at(n: field_init, source_indices: source_indices) if field_name == "" { [] } else { let field_value = field_init_node_value(n: field_init) @@ -4552,11 +4655,11 @@ fn collect_record_lit_field_struct_surfaces(parent: Node, field_init: Node, sour ExprRecordLit { parent_enum: _ } => let summary_key = variant_record_lit_summary_key(n: parent, source_indices: source_indices, variant_to_enum: variant_to_enum) if summary_key == "" { [] } else { - match map_get(type_summaries, summary_key) { + match type_summary_decided(index: type_summaries, key: summary_key) { Present { value: summary } => match map_get(summary.field_type_map, field_name) { Present { value: ft } => - if ft != "" && match map_get(type_summaries, ft) { + if ft != "" && match type_summary_decided(index: type_summaries, key: ft) { Present { value: fts } => match fts.repr { StructRepr => true @@ -4591,7 +4694,7 @@ fn collect_value_emit_type_surface_names(n: Node, source_indices: Map if parent != "" { [parent] } else { [] } + Present { value: parent } => if parent != "" { [qualified_last_segment(name: parent)] } else { [] } Absent => [] } unique_strings(items: concat(from_inferred_list, from_variant)) @@ -4652,15 +4755,15 @@ fn imported_names_in_use_line(line: String) -> List { data reference_derived_use_lines_note: String = "emit_import_closure_root (§5). emit_imports wires a per-module use-line only for names in an authored import list. Namespace-only resolution (post-PR 6848) references cross-module names WITHOUT importing them, so the ref is KNOWN but the use-line is declined (advisory UnlistedImportUse, is_error_diagnostic=false) — a §5 fail-open (⊤-as-ignorance) that emits invalid Rust (E0422/E0433/E0425 downstream). This pass derives the missing use-lines from the SAME resolver signal, split by reference kind onto its precise authority (§2 Realization: one closure, two consumers): (1) TYPE refs come from the resolver's UnlistedImportUse diagnostics (04_resolve.dag resolve_node, masked && not-in-SVN at type positions) threaded through ResolvedGraph.diagnostics — zero-drift by construction, the resolver already applied its SVN mask AT RESOLVE TIME; (2) VALUE-position refs come from collect_value_ref_names, a NARROW walk that structurally excludes the type over-collection classes (container heads, field labels, deep-inferred type names): fn/data refs (FunctionValueBinding ExprVar + ExprCall callee names) AND record-literal type constructions (ExprRecordLit type name + its parent_enum) — the latter matter because a GENERIC user type constructed as `T{..}` (e.g. RealizedStep) is grounded by resolve_node (masked flips false into the defining-module descent) so it NEVER fires UnlistedImportUse, yet its bare `T` still needs a use-line; (3) TYPE-surface refs on item signatures come from collect_item_emit_surface_names (collect_item_type_surface_names + collect_value_emit_type_surface_names over data bodies) over each item's type_annotation, param types, inferred Resolved return/signature, AND value-position record-literal / variant-parent-enum surfaces the emitter will qualify (e.g. UriScheme::Https in a data anchor) — covering masked-at-resolve TYPE positions (e.g. partial-import return type PilotWidget) that never enter UnlistedImportUse and are not ExprVar/ExprCall harvests. Registry cross-module resolve + is_known_variant fallback keep variant constructors routed through their parent's import. CONSTRUCTION WALL (ROOT 3, §5): a candidate that registry-resolves to a provider module MUST also pass provider_proven_exports_symbol (name_in_transitive_export_surface) before any use-line is synthesized — never a plausible guess from the bare-name registry alone (the v1_rt::member fabrication class: registry homonym without export proof). NOTE the SVN authority is resolve-time-only: env.source_visible_names is built in 04_infer's unresolved_env and consumed by resolve_node, but is NOT persisted onto TypedModule.type_env (emit reads empty_map), so emit MUST NOT re-apply an SVN filter — it would be a no-op that (worse, when non-empty) diverges from the resolve-time mask. The union is instead already-imported filtered (a name already carried by an authored import / prelude / carrier use-line is skipped — this is what keeps a fully-imported SEED module zero-drift: its refs are all in an import line) and kernel filtered (no E0252 against the runtime prelude), then LOCAL-DECL filtered (any name the module itself declares — local_decl_names from authored_name_at over items, plus local_type_names aliases/phantoms — is never an import candidate: the containment tree binds a bare ref to the module's own declaration before any cross-module lookup, and the bare-name registry is last-write-wins, so a dual-tree homonym — dag/std List/Map/GroupCompletion vs their src/v2/std twins — steals the registry row and would otherwise synthesize a SELF-COLLIDING pub-use, the E0255 std_dup class measured on the 2026-07-22 curated 4-module baseline), then cross-module registry-resolved (a ref the registry maps to this same module is skipped), then reuses emit_specific_import_block for variant/reexport correctness with a §5 direct-emit fallback (arm (c): the name resolved via registry to provider AND export-proven). A candidate that registry-resolves to nothing, or resolves but fails export proof, is left unsynthesized, and it never fabricates a use-line. STEP 2 HAS LANDED: the reason is no longer silent. Each such candidate carries a ReferenceDerivedCandidateDisposition -- CandidateRegistryAbsent or CandidateExportProofFailed, distinct because the remedies are opposite -- and CandidateExportProofFailed emits the typed, located, counted ReferenceDerivedImportExportUnproven. THE EMISSION IS NOT REFUSED, and the distinction matters because a reader of the phrase typed refusal will otherwise expect one: the diagnostic is ADVISORY, so emission completes and produces its files beside it. Measured on the required build lane at this branch head, entry:src/v2/compiler/00_compile.dag: emitted=175 blocking=0 -- so what step 2 closed is the SILENCE, not the emission. Whether the line stops is the severity question, and v1.compiler.core reference_derived_import_refusal_severity_note owns it, including why the blocking flip was executed and then falsified by its own first run over a second closure. SCOPE (emit_module_full): import-free modules run the full union (TYPE unlisted + VALUE refs) — the namespace-resolution case the post-PR-6848 regression is about. SUPERSEDED-MECHANISM, THIS CUT (eager-deer-389): the two sentences that follow describe the corpus_repr_is_faithful / HostNative gate, which NO LONGER EXISTS -- RustCorpusRepr and both its variants are deleted and the gate is gone, so import-bearing modules are no longer split by corpus mode. They are retained as the history of WHY the walk was gated at all (the spurious-use-line and seed zero-drift hazards below are real and still constrain any future gating), not as a live description; reference_use_lines_representation_invariant_note in this module carries the post-cut statement. Read them as quarry. AS WRITTEN BEFORE THE CUT: Import-bearing modules run reference_derived_use_lines ONLY when corpus_repr_is_faithful (FaithfulFreeMonoid / v2 namespace corpus): a partial-import namespace module (e.g. v2.std.node_query importing Outcome but calling outcome_with_diagnostics, or importing Outcome but annotating NamedEdgeTargetLookup) must synthesize BOTH the missing fn-value use-line AND the missing type use-line without duplicating names emit_imports already owns. HostNative import-bearing modules (v1 seed) get [] — running the walk there adds spurious/wrong use-lines (registry homonyms like kernel_span/is_type_variable) and breaks zero-drift seed regen." -fn expand_variant_payload_struct_imports(names: List, type_summaries: Map, variant_to_enum: Map) -> List { +fn expand_variant_payload_struct_imports(names: List, type_summaries: TypeSummaryIndex, variant_to_enum: Map) -> List { names |> flat_map(n => match map_get(variant_to_enum, n) { Present { value: enum_name } => if enum_name == "" { [] } else { - match map_get(type_summaries, variant_summary_key(enum_name: enum_name, variant_name: n)) { + match type_summary_decided(index: type_summaries, key: variant_summary_key(enum_name: enum_name, variant_name: n)) { Present { value: summary } => map_values(summary.field_type_map) |> filter(ft => - ft != "" && match map_get(type_summaries, ft) { + ft != "" && match type_summary_decided(index: type_summaries, key: ft) { Present { value: fts } => match fts.repr { StructRepr => true @@ -4716,14 +4819,14 @@ fn reference_is_host_realized_builtin(name: String) -> Bool { // fabricate. This arm carries no dissolution condition of its own — it dissolves with the text gate // it corrects, on the trigger reference_derived_authored_source_gate_note already declares. -fn reference_derived_variant_induced_parent_spelled(module_source: String, enum_name: String, type_summaries: Map, variant_to_enum: Map) -> Bool { - match map_get(type_summaries, enum_name) { +fn reference_derived_variant_induced_parent_spelled(module_source: String, enum_name: String, type_summaries: TypeSummaryIndex, variant_to_enum: Map) -> Bool { + match type_summary_decided(index: type_summaries, key: enum_name) { Present { value: summary } => match summary.repr { EnumRepr { unit_only: _ } => sorted_map_keys(summary.variant_name_set) |> any(vn => match map_get(variant_to_enum, vn) { - Present { value: parent } => parent == enum_name && reference_derived_candidate_spelled_in_module(module_source: module_source, name: vn) + Present { value: parent } => parent != "" && qualified_last_segment(name: parent) == qualified_last_segment(name: enum_name) && reference_derived_candidate_spelled_in_module(module_source: module_source, name: vn) Absent => false } ) @@ -4733,7 +4836,7 @@ fn reference_derived_variant_induced_parent_spelled(module_source: String, enum_ } } -fn reference_derived_candidate_authored(module_source: String, name: String, type_summaries: Map, variant_to_enum: Map) -> Bool { +fn reference_derived_candidate_authored(module_source: String, name: String, type_summaries: TypeSummaryIndex, variant_to_enum: Map) -> Bool { reference_derived_candidate_spelled_in_module(module_source: module_source, name: name) || reference_derived_variant_induced_parent_spelled(module_source: module_source, enum_name: name, type_summaries: type_summaries, variant_to_enum: variant_to_enum) } @@ -5010,12 +5113,12 @@ fn local_coproduct_variant_names(items: List, source_indices: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, type_summaries: Map, variant_to_enum: Map, in_type_position: Bool) -> ReferenceDerivedCandidateDisposition { +fn reference_derived_candidate_disposition(name: String, this_module_name: String, emit_info: EmitGraphInfo, registry: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, type_summaries: TypeSummaryIndex, variant_to_enum: Map, in_type_position: Bool) -> ReferenceDerivedCandidateDisposition { if is_known_variant(type_summaries: type_summaries, name: name) && !in_type_position { match map_get(variant_to_enum, name) { Present { value: parent } => if parent == "" { CandidateVariantParentUnresolved } - else { CandidateVariantDelegatedToParent { parent_enum: parent } } + else { CandidateVariantDelegatedToParent { parent_enum: qualified_last_segment(name: parent) } } Absent => CandidateVariantParentUnresolved } } else { @@ -5059,7 +5162,7 @@ fn reference_derived_candidate_disposition(name: String, this_module_name: Strin // vocabulary, so Vec and BTreeSet -- the Rust spellings of List and Set -- // slip a filter built to remove exactly this. // (b) OUT-OF-CLOSURE empty_map 33, Optional 25, and Optional's VARIANTS Present 47 and Absent 13 -// -- REAL .dag declarations in v2.std.collection and v2.std.optional whose +// -- REAL .dag declarations in v2.std.collection and std.optional whose // providers were not selected into the measured closure. Movable, and // precisely the closure-conditioned class this change exists to surface. // @@ -5666,7 +5769,7 @@ fn emit_module_full(typed_module: TypedModule, registry: Map, else { concat("\n", uncovered_svc_imports |> join(separator: "\n")) } let local_enum_uses = typed_module.items |> filter(item => is_type_def_item(item: item) && is_coproduct_type(n: item) - && !is_grounded_coproduct_native_alias(name: authored_name(env: scope.type_env, node: item)) + && !declaration_is_grounded_coproduct_native_alias(module_path: scope.type_env.module_path, decl_name: authored_name(env: scope.type_env, node: item)) && !rust_declaration_realizes_as_native_alias(module_path: authored_name(env: scope.type_env, node: m), decl_name: authored_name(env: scope.type_env, node: item)) && rust_kernel_grounded_type_decl(module_name: scope.module_name, item_text: authored_name(env: scope.type_env, node: item)) == none) |> map(item => concat("use self::", authored_name(env: scope.type_env, node: item), "::*;")) @@ -5733,7 +5836,7 @@ fn graph_type_import_module_path(name: String, import_module: String, mod_name: } } -fn is_import_graph_type_name(name: String, import_module: String, typed_modules: List, registry: Map, export_sets: Map>, type_summaries: Map, source_indices: Map, module_index: ModuleIndex) -> Bool { +fn is_import_graph_type_name(name: String, import_module: String, typed_modules: List, registry: Map, export_sets: Map>, type_summaries: TypeSummaryIndex, source_indices: Map, module_index: ModuleIndex) -> Bool { if has_physical_type_def_in_module_filename(rhs_name: name, mod_filename: module_to_filename(name: import_module), typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { true } else if match reexport_source_module_name(name: name, import_module: import_module, typed_modules: typed_modules, export_sets: export_sets, source_indices: source_indices, module_index: module_index) { @@ -5741,7 +5844,11 @@ fn is_import_graph_type_name(name: String, import_module: String, typed_modules: Absent => false } { true - } else if is_enum_in_summaries(type_summaries: type_summaries, type_name: name) { + } else if match is_enum_in_summaries(type_summaries: type_summaries, type_name: name) { + QuestionDecided { value: v } => v + QuestionNameAmbiguous { leaf: _ } => false + QuestionNotDeclared => false + } { false } else if is_known_variant(type_summaries: type_summaries, name: name) { false @@ -6033,13 +6140,17 @@ fn reexport_source_module_name_with_visited(name: String, import_module: String, } } -fn import_module_enum_scope(import_module: String, registry: Map, type_summaries: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { +fn import_module_enum_scope(import_module: String, registry: Map, type_summaries: TypeSummaryIndex, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { let physical = enum_names_in_module(module_name: import_module, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) let reexport_parents = match map_get(export_sets, import_module) { Present { value: exported } => sorted_map_keys(exported) |> filter(n => is_known_variant(type_summaries: type_summaries, name: n) - && is_enum_in_summaries(type_summaries: type_summaries, type_name: n) == false + && match is_enum_in_summaries(type_summaries: type_summaries, type_name: n) { + QuestionDecided { value: v } => v == false + QuestionNotDeclared => true + QuestionNameAmbiguous { leaf: _ } => false + } ) |> map(n => match reexport_variant_parent_in_import_module( variant_name: n, @@ -6224,7 +6335,7 @@ fn explicit_import_source_module_for_name(name: String, import_module: String, t } } -fn reexport_variant_parent_in_import_module(variant_name: String, import_module: String, registry: Map, type_summaries: Map, typed_modules: List, export_sets: Map>, source_indices: Map, module_index: ModuleIndex) -> String? { +fn reexport_variant_parent_in_import_module(variant_name: String, import_module: String, registry: Map, type_summaries: TypeSummaryIndex, typed_modules: List, export_sets: Map>, source_indices: Map, module_index: ModuleIndex) -> String? { match reexport_source_module_name(name: variant_name, import_module: import_module, typed_modules: typed_modules, export_sets: export_sets, source_indices: source_indices, module_index: module_index) { Absent => Absent Present { value: src_mod } => @@ -6574,7 +6685,7 @@ fn is_emittable_parametric_type_alias_item(item: Node, item_text: String, source } } -fn import_variant_parent_for_name(n: String, import_module: String, registry: Map, type_summaries: Map, typed_modules: List, export_sets: Map>, source_indices: Map, module_index: ModuleIndex, imported_enums: List, import_module_enums: List) -> String { +fn import_variant_parent_for_name(n: String, import_module: String, registry: Map, type_summaries: TypeSummaryIndex, typed_modules: List, export_sets: Map>, source_indices: Map, module_index: ModuleIndex, imported_enums: List, import_module_enums: List) -> String { if is_import_graph_type_name(name: n, import_module: import_module, typed_modules: typed_modules, registry: registry, export_sets: export_sets, type_summaries: type_summaries, source_indices: source_indices, module_index: module_index) { "" } else if import_module_enums |> any(e => e == n) { @@ -6884,7 +6995,7 @@ fn emit_specific_import_use_lines(import_module: String, mod_name: String, filte ) let main_lines = concat(direct_lines, parent_main_lines) let variant_lines = parent_list |> flat_map(parent => - if is_grounded_coproduct_native_alias(name: parent) || rust_declaration_realizes_as_native_alias(module_path: import_module, decl_name: parent) { [] } else { + if declaration_is_grounded_coproduct_native_alias(module_path: import_module, decl_name: parent) || every_declarer_is_grounded_coproduct_native_alias(decls: emit_info.type_decl_items, name: parent) || rust_declaration_realizes_as_native_alias(module_path: import_module, decl_name: parent) { [] } else { let variants = deduped_names |> filter(n => if n == "None" || n == "Some" { false @@ -6918,7 +7029,7 @@ fn emit_specific_import_use_lines(import_module: String, mod_name: String, filte let final_imported_enums = top_level |> filter(n => import_module_enums |> any(e => e == n)) let wildcard_enum_lines = final_imported_enums |> filter(en => parent_list |> any(p => p == en) == false - && !is_grounded_coproduct_native_alias(name: en) + && !declaration_is_grounded_coproduct_native_alias(module_path: import_module, decl_name: en) && !rust_declaration_realizes_as_native_alias(module_path: import_module, decl_name: en) && rust_kernel_grounded_type_decl(module_name: import_module, item_text: en) == none) |> map(en => RustUseLine { target_module: mod_name, text: concat("use crate::", mod_name, "::", en, "::*;") }) @@ -7281,7 +7392,7 @@ The predicate was `has_physical_type_def_in_module_filename` — field type PHYS INCREMENT 2 (generic-argument axis, #6986): build_field_type_map also walks the resolved field-type NODE TREE via collect_type_node_import_surface_names (04_emit_info.dag), populating TypeSummary.field_import_surface_names; this synth consumes that list so List admits CacheEvidence (field_type_map still maps field→HEAD for lookup). Witness: field_import_surface_generic_arg_test. Re-probe 2026-07-21: materialization_carriers CacheEvidence E0422 cleared; first error advanced to E0425 cannot find value extdeps (namespace/dotted-path class — distinct blocker)." -fn module_data_field_struct_import_names(items: List, type_summaries: Map, import_module: String, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { +fn module_data_field_struct_import_names(items: List, type_summaries: TypeSummaryIndex, import_module: String, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { unique_strings(items: items |> filter(item => item.module_item_kind == ModuleItemDataValue) |> flat_map(item => { @@ -7292,12 +7403,12 @@ fn module_data_field_struct_import_names(items: List, type_summaries: Map< if type_name == "" { [] } else { - match map_get(type_summaries, type_name) { + match type_summary_decided(index: type_summaries, key: type_name) { Present { value: summary } => summary.field_import_surface_names |> filter(field_type => field_type != "" && name_in_transitive_export_surface(name: field_type, module_name: import_module, visited: [], export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) - && match map_get(type_summaries, field_type) { + && match type_summary_decided(index: type_summaries, key: field_type) { Present { value: ft } => match ft.repr { StructRepr => true @@ -7853,7 +7964,7 @@ fn emit_type_def_from_connective(item: Node, recursive_types: Set, share let clone_bound_refusal = emit_item_clone_bound_refusal(item: item, item_name: item_text, emit_info: emit_info, source_indices: env.source_indices) let struct_text = emit_struct_from_children(name: item_text, type_params: type_params, generic_param_names: generic_param_names, header_clone_param_names: header_clone_param_names, children: item.children, recursive_types: recursive_types, shared_types: shared_types, sealed: sealed, deserialize_forbidden: deserialize_forbidden, env: env, emit_info: emit_info) if clone_bound_refusal == "" { struct_text } else { concat(clone_bound_refusal, "\n", struct_text) } - } else if is_host_optional_carrier_alias(name: item_text) { + } else if declaration_owns_host_option(module_path: env.module_path, decl_name: item_text) { let type_params = emit_type_params(params: item.params, source_indices: env.source_indices) let elem_csv = item.params |> map(p => to_pascal(name: generic_param_name_at(n: p, source_indices: env.source_indices))) |> join(separator: ", ") concat(rust_visibility_prefix(), "type ", item_text, type_params, " = Option<", elem_csv, ">;") @@ -7941,7 +8052,7 @@ fn rust_phantom_marker_inner(unused: List) -> String { fn rust_phantom_field_name() -> String { "_phantom" } fn type_has_fn_fields(name: String, emit_info: EmitGraphInfo) -> Bool { - match map_get(emit_info.type_summaries, name) { + match type_summary_decided(index: emit_info.type_summaries, key: name) { Present { value: ts } => ts.has_fn_fields Absent => false } @@ -10177,25 +10288,32 @@ fn emit_pattern(pattern: MatchPattern, path_prefix: List, shared_types: } } -fn pattern_parent_enum(name: String, parent_enum: String?, scrut_type: String, type_summaries: Map) -> String? { - let scrut_is_known_enum = scrut_type != "" && is_enum_type_name(type_name: scrut_type, type_summaries: type_summaries) +fn rust_ambiguous_type_name_refusal(leaf: String) -> String { + concat("compile_error!(\"ambiguous type name '", leaf, "': declarations disagree\")") +} + +fn pattern_parent_enum(name: String, parent_enum: String?, scrut_type: String, type_summaries: TypeSummaryIndex) -> String? { if parent_enum != none { parent_enum - } else if scrut_is_known_enum { - Present { value: scrut_type } - } else { + } else if scrut_type == "" { unique_variant_parent(type_summaries: type_summaries, variant_name: name) + } else { + match is_enum_type_name(type_name: scrut_type, type_summaries: type_summaries) { + QuestionDecided { value: true } => Present { value: scrut_type } + QuestionNameAmbiguous { leaf: leaf } => Present { value: rust_ambiguous_type_name_refusal(leaf: leaf) } + _ => unique_variant_parent(type_summaries: type_summaries, variant_name: name) + } } } -fn unique_variant_parent(type_summaries: Map, variant_name: String) -> String? { - let parent_matches = sorted_map_keys(type_summaries) - |> filter(type_name => - is_enum_type_name(type_name: type_name, type_summaries: type_summaries) && - variant_belongs_to_enum(type_summaries: type_summaries, variant_name: variant_name, enum_name: type_name) - ) +fn unique_variant_parent(type_summaries: TypeSummaryIndex, variant_name: String) -> String? { + let parent_matches = type_summary_values(index: type_summaries) + |> filter(summary => summary_is_enum_with_variant(summary: summary, variant_name: variant_name)) if parent_matches |> count == 1 { - parent_matches |> first + match parent_matches |> first { + Present { value: summary } => Present { value: summary.name } + Absent => none + } } else { none } @@ -10215,8 +10333,19 @@ fn is_optional_variant_name(name: String) -> Bool { name == "Present" || name == "Absent" || name == "Some" || name == "None" } +// A parent arrives as a bare name, or -- from variant_to_enum, whose values are owners' identities -- +// as `.`. An identity is decided by the declaration it names (the kernel optional's +// mint row and rust_host_option_carrier_declarations); only a bare name keeps the spelling rule. fn is_optional_like_parent_name(name: String) -> Bool { - name == kernel_optional_mint_name || is_host_diagnostics_carrier_alias(name: name) + if contains(name, ".") { + let segments = name |> split(delimiter: ".") + let module_path = segments |> take((segments |> count) - 1) |> join(separator: ".") + let decl_name = qualified_last_segment(name: name) + declaration_owns_host_option(module_path: module_path, decl_name: decl_name) + || declaration_ref_in_list(target: decl_ref(module_path: module_path, decl_name: decl_name), refs: rust_host_option_carrier_declarations) + } else { + name == kernel_optional_mint_name || is_host_diagnostics_carrier_alias(name: name) + } } fn is_some_like_variant_name(name: String) -> Bool { @@ -10565,7 +10694,7 @@ fn analyze_rc_pattern(pattern: MatchPattern, scrut_type: String, shared_types: S let matches_rc_variant = match resolved_parent { Present { value: enum_name } => set_contains(shared_types, enum_name) Absent => - match map_get(emit_info.type_summaries, bare_n) { + match type_summary_decided(index: emit_info.type_summaries, key: bare_n) { Present { value: _ } => set_contains(shared_types, bare_n) Absent => false } @@ -10931,7 +11060,7 @@ fn rust_as_ref_let_is_irrefutable(pattern: MatchPattern, emit_info: EmitGraphInf let resolved = pattern_parent_enum(name: qualified_last_segment(name: n), parent_enum: parent, scrut_type: "", type_summaries: emit_info.type_summaries) match resolved { Present { value: enum_name } => - match map_get(emit_info.type_summaries, enum_name) { + match type_summary_decided(index: emit_info.type_summaries, key: enum_name) { Present { value: summary } => (sorted_map_keys(summary.variant_name_set) |> count) <= 1 Absent => false } @@ -11096,7 +11225,7 @@ fn freemonoid_empty_from_variant_parent(leaf_name: String, enum_name: String) -> fn freemonoid_empty_from_emit_info(leaf_name: String, emit_info: EmitGraphInfo) -> Bool { leaf_name == "Empty" && match map_get(emit_info.variant_to_enum, "Empty") { - Present { value: p } => p == "FreeMonoid" + Present { value: p } => qualified_last_segment(name: p) == "FreeMonoid" Absent => false } } @@ -11111,7 +11240,10 @@ fn emit_freemonoid_empty_variant_body() -> String { fn effective_variant_parent_from_enum_lookup(leaf_name: String, rt: Node, binding_kind: VarBindingKind?, emit_info: EmitGraphInfo, source_indices: Map) -> String? { let rt_name = authored_name_at(source_indices: source_indices, node: rt) - if rt.ident_span != none && rt_name != leaf_name && variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: leaf_name, enum_name: rt_name) { + if rt.ident_span != none && rt_name != leaf_name && match variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: leaf_name, enum_name: rt_name) { + QuestionDecided { value: v } => v + _ => false + } { Present { value: rt_name } } else { variant_parent_from_binding_kind(binding_kind: binding_kind) @@ -11129,7 +11261,7 @@ fn effective_variant_parent_from_resolved(leaf_name: String, rt: Node, binding_k fn effective_variant_parent(name: String, binding_kind: VarBindingKind?, resolved_type: InferredNode?, emit_info: EmitGraphInfo, source_indices: Map) -> String? { let leaf_name = value_ref_qualified_leaf(name: name) let cached = match map_get(emit_info.variant_to_enum, leaf_name) { - Present { value: p } => if p != "" { Present { value: p } } else { none } + Present { value: p } => if p != "" { Present { value: qualified_last_segment(name: p) } } else { none } Absent => none } match cached { @@ -12055,11 +12187,15 @@ fn emit_rust_expr_record_lit(expr: Node, registry: Map, scope: let variant_name = match tn { Present { value: n } => n Absent => "" } let concrete_peel_would_erase_optional_ctor = is_optional_variant_name(name: variant_name) - && !variant_belongs_to_enum( + && match variant_belongs_to_enum( type_summaries: emit_info.type_summaries, variant_name: variant_name, enum_name: authored_name_at(source_indices: si, node: expanded_rt) - ) + ) { + QuestionDecided { value: v } => v == false + QuestionNotDeclared => true + QuestionNameAmbiguous { leaf: _ } => false + } let peeled_type_name = if parent_enum == none && expanded_rt.connective == Conj && expanded_rt.ident_span != none && !concrete_peel_would_erase_optional_ctor { let concrete = authored_name_at(source_indices: si, node: expanded_rt) if concrete != "" && concrete != variant_name { Present { value: concrete } } else { tn } @@ -12273,13 +12409,16 @@ fn emit_cloned_arg(texpr: Node, registry: Map, scope: InferSco emit_typed_expr(texpr: texpr, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024) } -fn is_enum_type_name(type_name: String, type_summaries: Map) -> Bool { +fn is_enum_type_name(type_name: String, type_summaries: TypeSummaryIndex) -> TypeSummaryQuestion { is_enum_in_summaries(type_summaries: type_summaries, type_name: type_name) } fn contextual_variant_parent_from_type_name(variant_name: String, resolved_type: Node, emit_info: EmitGraphInfo, source_indices: Map) -> String? { let rt_name = authored_name_at(source_indices: source_indices, node: resolved_type) - if resolved_type.ident_span != none && rt_name != variant_name && variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_name, enum_name: rt_name) { + if resolved_type.ident_span != none && rt_name != variant_name && match variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_name, enum_name: rt_name) { + QuestionDecided { value: v } => v + _ => false + } { Present { value: rt_name } } else { none @@ -12297,7 +12436,10 @@ fn contextual_variant_parent_absent(variant_name: String, resolved_type: Node, e fn contextual_variant_parent(variant_name: String, parent_enum: String?, resolved_type: Node, emit_info: EmitGraphInfo, source_indices: Map) -> String? { match parent_enum { Present { value: explicit_parent } => - if variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_name, enum_name: explicit_parent) { + if match variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_name, enum_name: explicit_parent) { + QuestionDecided { value: v } => v + _ => false + } { Present { value: explicit_parent } } else { none } Absent => contextual_variant_parent_absent(variant_name: variant_name, resolved_type: resolved_type, emit_info: emit_info, source_indices: source_indices) @@ -12471,7 +12613,7 @@ fn rust_call_arg_fail_closed_unwrap(arg_str: String, arg: Node, callee: ItemInfo match function_value_params(params: info.params) |> skip(idx) |> first { Present { value: param } => let param_type = param_node_type_expr(n: param) - let param_required = param_type.return_cardinality != CardOptional && !is_host_optional_carrier_type(n: param_type, source_indices: source_indices) && !rust_param_type_is_type_variable(param_type: param_type, source_indices: source_indices) + let param_required = param_type.return_cardinality != CardOptional && !is_host_optional_carrier_type(n: param_type, source_indices: source_indices, env: empty_type_env()) && !rust_param_type_is_type_variable(param_type: param_type, source_indices: source_indices) let arg_optional = resolved_type(n: arg).return_cardinality == CardOptional && !rust_call_arg_is_function_value(arg: arg) if param_required && arg_optional { concat(arg_str, ".expect(\"fail-closed: an optional value flowed into non-optional parameter ", to_string(value: idx), " of ", func, " (empty Optional at runtime)\")") @@ -13787,7 +13929,7 @@ fn freemonoid_match_arm_for(arms: List, variant: String) -> Node? { }) |> first } -fn arm_resolved_parent_enum(arm: Node, scrut_type: String, type_summaries: Map) -> String? { +fn arm_resolved_parent_enum(arm: Node, scrut_type: String, type_summaries: TypeSummaryIndex) -> String? { match arm_pattern(n: arm) { VariantPattern { name: n, parent_enum: pe, field_bindings: _, parent_identity: _ } => pattern_parent_enum(name: qualified_last_segment(name: n), parent_enum: pe, scrut_type: scrut_type, type_summaries: type_summaries) @@ -13814,7 +13956,7 @@ fn freemonoid_catchall_arm(arms: List) -> Node? { }) |> first } -fn arms_are_freemonoid_coproduct(arms: List, scrut_type: String, type_summaries: Map) -> Bool { +fn arms_are_freemonoid_coproduct(arms: List, scrut_type: String, type_summaries: TypeSummaryIndex) -> Bool { let has_empty = match freemonoid_match_arm_for(arms: arms, variant: "Empty") { Present { value: _ } => true Absent => false } let has_cons = match freemonoid_match_arm_for(arms: arms, variant: "Cons") { Present { value: _ } => true Absent => false } let empty_is_fm = match freemonoid_match_arm_for(arms: arms, variant: "Empty") { @@ -14925,7 +15067,10 @@ fn emit_field_value_with_context(field_value: Node, struct_node: Node, outer_typ } let corrected_parent = match expected_type { Present { value: et } => - if variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_name, enum_name: et) { + if match variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_name, enum_name: et) { + QuestionDecided { value: v } => v + _ => false + } { Present { value: et } } else { pe } Absent => pe @@ -14969,10 +15114,10 @@ fn record_field_expected_type(struct_node: Node, outer_type_name: String?, field // struct per anonymous record literal. The count needs no order, so it reads the keys unsorted. The // literal's names are unique (02_parse refuses a repeated field init), so presence plus equal count // is exactly set equality, as before. -fn struct_candidates_by_field_names(field_names: List, type_summaries: Map) -> List { +fn struct_candidates_by_field_names(field_names: List, type_summaries: TypeSummaryIndex) -> List { let n_fields = field_names |> count if n_fields == 0 { return [] } - map_values(type_summaries) |> filter(summary => + type_summary_values(index: type_summaries) |> filter(summary => match summary.repr { StructRepr => field_names |> all(fn_name => map_contains_key(summary.field_type_map, fn_name)) @@ -15026,7 +15171,7 @@ fn effectful_self_recursion_diagnostics(tm: TypedModule, registry: Map, field_type_hints: Map, type_summaries: Map) -> List { +fn anonymous_record_struct_candidates(field_names: List, field_type_hints: Map, type_summaries: TypeSummaryIndex) -> List { let candidates = struct_candidates_by_field_names(field_names: field_names, type_summaries: type_summaries) if candidates |> count <= 1 { candidates } else { @@ -15046,7 +15191,7 @@ fn anonymous_record_struct_candidates(field_names: List, field_type_hint } } -fn ambiguous_anonymous_record_literal_diagnostics(n: Node, type_summaries: Map, source_indices: Map, module_name: String) -> List { +fn ambiguous_anonymous_record_literal_diagnostics(n: Node, type_summaries: TypeSummaryIndex, source_indices: Map, module_name: String) -> List { let current = match n.expr_data { ExprRecordLit { parent_enum: _ } => match record_lit_type_name_at(texpr: n, source_indices: source_indices) { @@ -15077,7 +15222,7 @@ fn ambiguous_anonymous_record_literal_diagnostics(n: Node, type_summaries: Map, field_type_hints: Map, type_summaries: Map) -> String? { +fn find_struct_name_by_fields(field_names: List, field_type_hints: Map, type_summaries: TypeSummaryIndex) -> String? { let candidates = anonymous_record_struct_candidates(field_names: field_names, field_type_hints: field_type_hints, type_summaries: type_summaries) if candidates |> count == 1 { match candidates |> first { @@ -15087,7 +15232,7 @@ fn find_struct_name_by_fields(field_names: List, field_type_hints: Map, type_summaries: Map) -> String? { +fn find_unique_struct_name_by_fields(field_names: List, type_summaries: TypeSummaryIndex) -> String? { let candidates = struct_candidates_by_field_names(field_names: field_names, type_summaries: type_summaries) if candidates |> count == 1 { match candidates |> first { @@ -15108,7 +15253,7 @@ fn emit_typed_record_lit(type_name: String?, fields: List, parent_enum: St Present { value: sn } => Present { value: sn } Absent => let rt_name = authored_name_at(source_indices: scope.type_env.source_indices, node: resolved_type) - if resolved_type.ident_span != none && map_contains_key(emit_info.type_summaries, rt_name) { + if resolved_type.ident_span != none && (type_summary_decided(index: emit_info.type_summaries, key: rt_name) != none) { Present { value: rt_name } } else { none } } @@ -15193,7 +15338,7 @@ fn emit_typed_record_lit(type_name: String?, fields: List, parent_enum: St if keyed_container_has_target_inhabitant(container_name: tn, target: Rust) { return "panic!(\"record-shaped carrier has no realization in the selected Rust target inhabitant\")" } - let tn_is_known_struct = map_contains_key(emit_info.type_summaries, tn) + let tn_is_known_struct = (type_summary_decided(index: emit_info.type_summaries, key: tn) != none) let ctor_name = if tn_is_known_struct { tn } else { let resolved_struct = resolve_node(n: resolved_type, env: scope.type_env, module_name: scope.module_name).resolved @@ -15214,7 +15359,10 @@ fn emit_typed_record_lit(type_name: String?, fields: List, parent_enum: St let rt_name = qualified_last_segment(name: authored_name_at(source_indices: si, node: resolved_type)) if resolved_type.ident_span != none && rt_name != variant_surface_name && !rt_is_type_var && rt_name != "Error" - && variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_surface_name, enum_name: rt_name) { + && match variant_belongs_to_enum(type_summaries: emit_info.type_summaries, variant_name: variant_surface_name, enum_name: rt_name) { + QuestionDecided { value: v } => v + _ => false + } { Present { value: rt_name } } else { bare_parent_enum diff --git a/src/v1/compiler_tests_rust.dag b/src/v1/compiler_tests_rust.dag index f4fec02f769..93c46ad5ffe 100644 --- a/src/v1/compiler_tests_rust.dag +++ b/src/v1/compiler_tests_rust.dag @@ -1782,6 +1782,101 @@ fn ct_unbound_reference_to_a_twice_declared_leaf_refuses_test() -> String { ) } +// A same-leaf declaration in one module does not change what another module emits. +fn ct_a_coproduct_named_optional_emits_as_its_own_enum_test() -> String { + [ + " // A COPRODUCT NAMED Optional EMITS AS ITS OWN ENUM. still-raven-321's fixture,\n", + " // fixtures/native_emission_controls_optional_collision.dag, is a non-kernel declaration that shares\n", + " // the kernel mint's leaf. Host-Option is decided by declaration (v1.compiler.emit_rust\n", + " // declaration_owns_host_option over gunbc.structural_realization_bindings kernel_mint_declaration_rows),\n", + " // so its positions name its own enum. THE RED is the leaf rule this replaced: every position rendered\n", + " // as Option<..> and the variants were never emitted (E0425 cannot find CollisionWrapped). The fixture\n", + " // lives outside the source roots, because a second Optional in the accepted corpus is a leaf-name fork,\n", + " // so it is compiled here, from its file, beside a kernel std.optional. Its one import line names a\n", + " // kernel type and is dropped so the pair compiles standalone.\n", + " #[test]\n", + " fn a_coproduct_named_optional_emits_as_its_own_enum() {\n", + " use crate::v1_compiler_compile::SourceFile;\n", + " let collision = read_dag(\"fixtures/native_emission_controls_optional_collision.dag\").replace(\"import std.types \{ Int \}\\n\", \"\");\n", + " let sources = vec![\n", + " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/optional.dag\".to_string(), content: \"module std.optional\\n\\ntype Optional\\n = Present { value: T }\\n | Absent\\n\".to_string() }),\n", + " std::rc::Rc::new(SourceFile { path: \"fixtures/native_emission_controls_optional_collision.dag\".to_string(), content: collision }),\n", + " ];\n", + " let result = crate::v1_compiler_compile::compile_sources(std::rc::Rc::new(sources.into()), crate::v1_compiler_artifact::RenderTarget::Rust);\n", + " let emitted = result.files.iter().find(|f| f.path.contains(\"native_emission_controls_optional_collision\")).map(|f| f.content.clone()).unwrap_or_default();\n", + " assert!(emitted.contains(\"pub enum Optional\") && emitted.contains(\"CollisionWrapped\"), \"the collision coproduct must emit as its own enum:\\n\{emitted}\");\n", + " assert!(!emitted.contains(\"Option<\") && !emitted.contains(\"compile_error!\"), \"no position of the collision coproduct may realize as the host Option:\\n\{emitted}\");\n", + " }\n", + "\n", + ] |> join(separator: "") +} + +fn ct_unstamped_bare_optional_follows_the_lookup_binding_order_test() -> String { + [ + " // AN UNSTAMPED BARE `Optional` FOLLOWS THE TYPECHECKER'S lookup_binding ORDER: own file, then\n", + " // the file's named import (followed through re-exports), then the kernel\n", + " // (v1.compiler.infer_env bare_occurrence_binding). The member references of a coproduct body reach\n", + " // the emitter from the type environment's copy with no Node.declaration, so the census route is\n", + " // the emitter's own decision. THE RED is the importer: with the kernel ahead of the named import\n", + " // (the order direct_import_export_precedence_note states) its payload routes kernel_mint to\n", + " // std.optional, measured on gunbc#13454 at 57551c4b. The control keeps a module that names\n", + " // Optional without importing it on the kernel arm.\n", + " #[test]\n", + " fn unstamped_bare_optional_follows_the_lookup_binding_order() {\n", + " use crate::v1_compiler_compile::SourceFile;\n", + " let sources = vec![\n", + " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/optional.dag\".to_string(), content: \"module std.optional\\n\\ntype Optional\\n = Present { value: T }\\n | Absent\\n\".to_string() }),\n", + " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/collision.dag\".to_string(), content: \"module hom.collision\\n\\ntype Optional\\n = CollisionWrapped { value: Int }\\n | CollisionEmpty\\n\".to_string() }),\n", + " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/importer.dag\".to_string(), content: \"module hom.importer\\n\\nimport hom.collision { Optional }\\n\\ntype HeldChoice\\n = HeldOptional { held: Optional }\\n | HeldNothing\\n\".to_string() }),\n", + " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/plain.dag\".to_string(), content: \"module hom.plain\\n\\ntype PlainChoice\\n = PlainHeld { held: Optional }\\n | PlainNothing\\n\".to_string() }),\n", + " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/user.dag\".to_string(), content: \"module hom.user\\n\\nimport hom.importer { HeldChoice }\\nimport hom.plain { PlainChoice }\\n\\nfn pick(h: HeldChoice, p: PlainChoice) -> Int {\\n 1\\n}\\n\".to_string() }),\n", + " ];\n", + " let receipt = crate::v1_tests_claim_carrier_realization_census::typed_census_from_sources(std::rc::Rc::new(sources.into()));\n", + " assert!(!receipt.starts_with(\"REFUSED\"), \"\{receipt}\");\n", + " let routes = |enclosing: &str| -> Vec {\n", + " receipt.lines().skip(1).map(|l| l.split('\\t').collect::>())\n", + " .filter(|c| c[1] == enclosing && c[2] == \"declaration_field\" && c[3] == \"Optional\")\n", + " .map(|c| c[13].to_string()).collect()\n", + " };\n", + " let held = routes(\"HeldChoice\");\n", + " assert!(!held.is_empty() && held.iter().all(|r| r == \"referencing_module_import:Resolved:hom.collision.Optional\"), \"the imported Optional must route to the import, never the kernel mint:\\n\{receipt}\");\n", + " let plain = routes(\"PlainChoice\");\n", + " assert!(!plain.is_empty() && plain.iter().all(|r| r == \"kernel_mint:Resolved:std.optional.Optional\"), \"an unimported Optional is the kernel's:\\n\{receipt}\");\n", + " assert!(!receipt.contains(\"LeafAmbiguous:Optional\"), \"\{receipt}\");\n", + " }\n", + "\n", + ] |> join(separator: "") +} + +fn ct_same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged_test() -> String { + concat( + " // A SAME-LEAF TYPE ANYWHERE MUST NOT CHANGE ANOTHER MODULE'S EMISSION. hom.user returns the kernel\n", + " // optional's Absent; hom.edge declares an unrelated enum that also has an Absent variant. With the\n", + " // leaf-keyed type summaries, adding hom.coll (a coproduct it declares as Optional) replaced the\n", + " // kernel Optional's summary, so Absent stopped being an Optional variant and hom.user emitted\n", + " // Rc::new(Lookup::Absent) where it had emitted None. Keyed by declaration, both summaries stand:\n", + " // hom.user's file is byte-identical with and without hom.coll, and its Absent is the host None.\n", + " #[test]\n", + " fn same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged() {\n", + " use crate::v1_compiler_compile::SourceFile;\n", + " let src = |path: &str, content: &str| std::rc::Rc::new(SourceFile { path: path.to_string(), content: content.to_string() });\n", + " let optional = || src(\"fixtures/same_leaf_optional/optional.dag\", \"module std.optional\\n\\ntype Optional\\n = Present { value: T }\\n | Absent\\n\");\n", + " let edge = || src(\"fixtures/same_leaf_optional/edge.dag\", \"module hom.edge\\n\\ntype Lookup\\n = Found { at: Int }\\n | Absent\\n\");\n", + " let user = || src(\"fixtures/same_leaf_optional/user.dag\", \"module hom.user\\nimport std.optional { Optional, Present, Absent }\\n\\nfn nothing_here(x: Int) -> Optional {\\n Absent\\n}\\n\");\n", + " let coll = || src(\"fixtures/same_leaf_optional/coll.dag\", \"module hom.coll\\n\\ntype Optional\\n = CollisionWrapped { value: Int }\\n | CollisionEmpty\\n\");\n", + " let emitted_user = |sources: Vec>| -> String {\n", + " let result = crate::v1_compiler_compile::compile_sources(std::rc::Rc::new(sources.into()), crate::v1_compiler_artifact::RenderTarget::Rust);\n", + " result.files.iter().find(|f| f.path.contains(\"hom_user\")).map(|f| f.content.clone()).unwrap_or_default()\n", + " };\n", + " let without = emitted_user(vec![optional(), edge(), user()]);\n", + " let with = emitted_user(vec![optional(), edge(), user(), coll()]);\n", + " assert!(without.contains(\"None\") && !without.contains(\"Lookup::Absent\"), \"the control: hom.user's Absent is the host None:\\n\{without}\");\n", + " assert_eq!(with, without, \"adding a same-leaf Optional elsewhere changed hom.user's emission\");\n", + " }\n", + "\n" + ) +} + // The referencing-module arm admits only a bare spelling: a qualified reference to another module's // declaration, arriving unstamped, is not decided by the referencing module's own same-leaf one. fn ct_qualified_reference_is_not_decided_by_the_local_declarer_test() -> String { @@ -1789,7 +1884,7 @@ fn ct_qualified_reference_is_not_decided_by_the_local_declarer_test() -> String " // A QUALIFIED REFERENCE IS NOT DECIDED BY THE LOCAL DECLARER. hom.local declares its own Slot\n", " // and ALSO names no.such.module.Slot, which resolve cannot bind, so the reference reaches the\n", " // emitter unstamped while two modules declare Slot. The referencing-module arm\n", - " // (v1.compiler.infer_emit_info type_decl_referencing_module_declarer) would pick the LOCAL Slot:\n", + " // (v1.compiler.infer_emit_info type_decl_occurrence_binding) would pick the LOCAL Slot:\n", " // the wrong-declarer class itself. It is admitted only for a bare spelling, so this refuses.\n", " // THE CONTROL is the same module without the second declarer: the spelling names a sole\n", " // declarer, and nothing refuses.\n", @@ -1965,6 +2060,9 @@ fn ct_coercion_tests() -> String { ct_same_leaf_type_declarations_emit_by_identity_test(), ct_unbound_reference_to_a_twice_declared_leaf_refuses_test(), ct_qualified_reference_is_not_decided_by_the_local_declarer_test(), + ct_same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged_test(), + ct_unstamped_bare_optional_follows_the_lookup_binding_order_test(), + ct_a_coproduct_named_optional_emits_as_its_own_enum_test(), ct_duplicate_type_parameter_refuses_test(), ct_resource_item_is_not_a_type_item_test()) } @@ -2393,7 +2491,11 @@ fn ct_diagnostics_carrier_grounding_test() -> String { " fn diagnostics_carrier_grounds_to_native_option() {\n", " assert!(crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_alias(\"Diagnostics\".to_string()));\n", " assert!(!crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_alias(\"Optional\".to_string()));\n", - " assert!(crate::v1_compiler_emit_rust::is_grounded_coproduct_native_alias(\"Diagnostics\".to_string()));\n", + " assert!(crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias(\"v2.std.diagnostic\".to_string(), \"Diagnostics\".to_string()));\n", + " // The host option is a DECLARATION, not a name: the kernel optional's declaration is it, and a\n", + " // coproduct another module declares as Optional is not.\n", + " assert!(crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias(\"std.optional\".to_string(), \"Optional\".to_string()));\n", + " assert!(!crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias(\"gunbc.instruments.native_emission_controls_optional_collision\".to_string(), \"Optional\".to_string()));\n", " let empty_shared = std::rc::Rc::new(im::OrdSet::new());\n", " assert_eq!(\n", " crate::v1_compiler_emit_rust::render_rust_diagnostics_carrier_applied(empty_shared.clone()),\n", diff --git a/src/v1/stage0/src/cli_run.rs b/src/v1/stage0/src/cli_run.rs index 194bcc1ee2f..e08887232c1 100644 --- a/src/v1/stage0/src/cli_run.rs +++ b/src/v1/stage0/src/cli_run.rs @@ -18324,10 +18324,14 @@ fn module_emit_repr_fingerprint( ) -> Result { use crate::v1_compiler_infer_emit_info::TypeSummary; + // Summaries are keyed by declaration identity (`.`), so a module's own types are + // read under its own path and never under a same-leaf declaration elsewhere in the closure. + let module_path = authored_name_at(source_indices.clone(), module.module.clone()); let type_names = module_defined_type_names(module, source_indices); let mut type_summaries = BTreeMap::::new(); for name in type_names { - if let Some(summary) = emit_info.type_summaries.get(&name) { + let key = format!("{module_path}.{name}"); + if let Some(summary) = emit_info.type_summaries.by_key.get(&key) { type_summaries.insert(name, summary.as_ref().clone()); } } @@ -22224,27 +22228,396 @@ fn extract_bool_witness_transport( (entry, function) } -fn defining_module_for_resolved_type( - graph: &ResolvedGraph, - source_indices: &HashMap>, +fn module_from_qualified_identity(identity: &str) -> Option { + let (module, name) = identity.rsplit_once('.')?; + if module.is_empty() || name.is_empty() { + None + } else { + Some(module.to_string()) + } +} + +fn defining_module_for_variant( variant_to_enum: &im::HashMap, - type_name: &str, + variant_name: &str, ) -> Option { - let si = Rc::new(source_indices.clone()); - for tm in graph.modules.iter() { - let mod_name = authored_name_at(si.clone(), tm.module.clone()); - if lookup_type_by_name(tm.type_env.clone(), type_name.to_string()).is_some() { - return Some(mod_name); + // variant_to_enum is keyed by VARIANT leaf. Values are owner identities `.`. + // No row, the collision sentinel "", or an unqualified identity has no module part: + // return None so the caller refuses. Do not scan type environments for a leaf match. + let parent_enum = variant_to_enum.get(variant_name)?; + module_from_qualified_identity(parent_enum) +} + +fn defining_module_for_type_identity( + type_summaries: &Rc, + identity: &str, +) -> Option { + // Exact declaration key only. type_summary_lookup / type_summary_by_leaf are leaf scans. + if !identity.contains('.') { + return None; + } + match (*crate::v1_compiler_infer_emit_info::type_summary_at_key( + type_summaries.clone(), + identity.to_string(), + )) + .clone() + { + crate::v1_compiler_infer_emit_info::TypeSummaryLookup::TypeSummaryFound { summary } => { + module_from_qualified_identity(&summary.key) } + _ => None, } - let parent_enum = variant_to_enum.get(type_name).cloned()?; - for tm in graph.modules.iter() { - let mod_name = authored_name_at(si.clone(), tm.module.clone()); - if lookup_type_by_name(tm.type_env.clone(), parent_enum.clone()).is_some() { - return Some(mod_name); +} + +fn defining_module_for_type_expr( + type_summaries: &Rc, + type_decls: &Rc, + source_indices: &HashMap>, + type_expr: &Rc, +) -> Option { + match (*crate::v1_compiler_infer_emit_info::type_summary_of_reference( + type_summaries.clone(), + type_decls.clone(), + type_expr.clone(), + Rc::new(source_indices.clone()), + )) + .clone() + { + crate::v1_compiler_infer_emit_info::TypeSummaryLookup::TypeSummaryFound { summary } => { + module_from_qualified_identity(&summary.key) } + _ => None, + } +} + +#[cfg(test)] +mod defining_module_lookup_tests { + use super::*; + + #[test] + fn bool_witness_claim_variant_resolves_to_verification_module() { + let mut variant_to_enum = im::HashMap::new(); + variant_to_enum.insert( + "BoolWitnessClaim".to_string(), + "v2.std.verification.UnifiedTestClaim".to_string(), + ); + variant_to_enum.insert( + "NodeCorpus".to_string(), + "v2.std.verification.UnifiedTestClaim".to_string(), + ); + assert_eq!( + defining_module_for_variant(&variant_to_enum, "BoolWitnessClaim"), + Some("v2.std.verification".to_string()), + "the owned-data BoolWitnessClaim path keys variant_to_enum by the variant leaf" + ); + assert_eq!( + defining_module_for_variant(&variant_to_enum, "UnifiedTestClaim"), + None, + "the coproduct leaf is not a variant key" + ); + } + + #[test] + fn unqualified_or_sentinel_variant_identity_refuses() { + let mut variant_to_enum = im::HashMap::new(); + variant_to_enum.insert("NoDot".to_string(), "UnifiedTestClaim".to_string()); + variant_to_enum.insert("Sentinel".to_string(), "".to_string()); + assert_eq!(defining_module_for_variant(&variant_to_enum, "NoDot"), None); + assert_eq!( + defining_module_for_variant(&variant_to_enum, "Sentinel"), + None + ); + assert_eq!( + defining_module_for_variant(&variant_to_enum, "Missing"), + None + ); + } + + #[test] + fn type_identity_uses_exact_summary_key_not_a_leaf() { + use crate::v1_compiler_infer_emit_info::{ + empty_type_summary_index, type_summary_index_insert, TypeRepr, TypeSummary, + }; + let summary = Rc::new(TypeSummary { + name: "UnifiedTestClaim".to_string(), + key: "v2.std.verification.UnifiedTestClaim".to_string(), + repr: Rc::new(TypeRepr::EnumRepr { unit_only: false }), + field_summaries: crate::v1_rt::rc_empty_map(), + field_type_map: crate::v1_rt::rc_empty_map(), + field_import_surface_names: Rc::new(im::Vector::new()), + variant_name_set: crate::v1_rt::rc_empty_map(), + generic_param_names: Rc::new(im::Vector::new()), + has_fn_fields: false, + }); + let index = type_summary_index_insert( + empty_type_summary_index(), + "v2.std.verification.UnifiedTestClaim".to_string(), + "UnifiedTestClaim".to_string(), + summary, + ); + assert_eq!( + defining_module_for_type_identity(&index, "v2.std.verification.UnifiedTestClaim"), + Some("v2.std.verification".to_string()) + ); + assert_eq!( + defining_module_for_type_identity(&index, "UnifiedTestClaim"), + None, + "a bare type leaf must not scan keys_by_leaf" + ); + } + + #[test] + fn user_type_named_like_a_known_variant_keeps_its_module() { + use crate::v1_compiler_infer_emit_info::{ + empty_type_decl_index, empty_type_summary_index, type_summary_index_insert, TypeRepr, + TypeSummary, + }; + let mut variant_to_enum = im::HashMap::new(); + variant_to_enum.insert( + "BoolWitnessClaim".to_string(), + "v2.std.verification.UnifiedTestClaim".to_string(), + ); + let summary = Rc::new(TypeSummary { + name: "BoolWitnessClaim".to_string(), + key: "owner.types.BoolWitnessClaim".to_string(), + repr: Rc::new(TypeRepr::StructRepr), + field_summaries: crate::v1_rt::rc_empty_map(), + field_type_map: crate::v1_rt::rc_empty_map(), + field_import_surface_names: Rc::new(im::Vector::new()), + variant_name_set: crate::v1_rt::rc_empty_map(), + generic_param_names: Rc::new(im::Vector::new()), + has_fn_fields: false, + }); + let index = type_summary_index_insert( + empty_type_summary_index(), + "owner.types.BoolWitnessClaim".to_string(), + "BoolWitnessClaim".to_string(), + summary, + ); + let source_indices = HashMap::new(); + let decls = empty_type_decl_index(); + assert_eq!( + defining_module_for_inferred_result( + &variant_to_enum, + &index, + &decls, + &source_indices, + None, + "owner.types.BoolWitnessClaim", + ), + Some("owner.types".to_string()), + "a user type identity named like a variant leaf is not routed to v2.std.verification" + ); + assert_eq!( + defining_module_for_variant(&variant_to_enum, "BoolWitnessClaim"), + Some("v2.std.verification".to_string()), + "the variant map still answers the record-lit arm" + ); + } + + fn synthetic_named_node(name: &str) -> Rc { + let span = no_span(); + Rc::new(Node { + occurrence_identity: Rc::new( + crate::std_occurrence_identity::NodeOccurrenceIdentity::OccurrenceSynthetic, + ), + name: name.to_string(), + ident: None, + span: span.clone(), + ident_span: Some(span), + children: Rc::new(im::Vector::new()), + connective: Connective::NoConnective, + params: Rc::new(im::Vector::new()), + inferred: None, + return_cardinality: Cardinality::Required, + uses: Rc::new(im::Vector::new()), + body: None, + transport: None, + properties: Rc::new(im::Vector::new()), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + module_item_kind: crate::v1_std_core::ParsedModuleItemKind::NotAModuleItem, + declaration_marker: crate::v1_std_core::DeclarationMarker::Unmarked, + declaration: None, + expr_data: Rc::new(ExprData::NoExprData), + }) + } + + #[test] + fn inferred_user_bool_witness_claim_keeps_its_module_at_initializer_ref() { + use crate::std_decl_ref::decl_ref; + use crate::v1_compiler_infer_emit_info::{ + empty_emit_graph_info, empty_type_decl_index, empty_type_summary_index, + type_decl_index_insert, type_summary_index_insert, TypeRepr, TypeSummary, + }; + + let mut variant_to_enum = im::HashMap::new(); + variant_to_enum.insert( + "BoolWitnessClaim".to_string(), + "v2.std.verification.UnifiedTestClaim".to_string(), + ); + + let mut type_node = (*synthetic_named_node("BoolWitnessClaim")).clone(); + type_node.declaration = Some(decl_ref( + "owner.types".to_string(), + "BoolWitnessClaim".to_string(), + )); + let type_node = Rc::new(type_node); + + let decl_item = type_node.clone(); + let decls = type_decl_index_insert( + empty_type_decl_index(), + "owner.types".to_string(), + "BoolWitnessClaim".to_string(), + decl_item, + ); + let summary = Rc::new(TypeSummary { + name: "BoolWitnessClaim".to_string(), + key: "owner.types.BoolWitnessClaim".to_string(), + repr: Rc::new(TypeRepr::StructRepr), + field_summaries: crate::v1_rt::rc_empty_map(), + field_type_map: crate::v1_rt::rc_empty_map(), + field_import_surface_names: Rc::new(im::Vector::new()), + variant_name_set: crate::v1_rt::rc_empty_map(), + generic_param_names: Rc::new(im::Vector::new()), + has_fn_fields: false, + }); + let summaries = type_summary_index_insert( + empty_type_summary_index(), + "owner.types.BoolWitnessClaim".to_string(), + "BoolWitnessClaim".to_string(), + summary, + ); + + let mut emit_info = (*empty_emit_graph_info()).clone(); + emit_info.variant_to_enum = Rc::new(variant_to_enum); + emit_info.type_summaries = summaries; + emit_info.type_decl_items = decls; + + let mut body = (*synthetic_named_node("")).clone(); + body.inferred = Some(Rc::new(InferredNode::Resolved { node: type_node })); + let body = Rc::new(body); + + let graph = ResolvedGraph { + modules: Rc::new(im::Vector::new()), + item_registry: Rc::new(im::HashMap::new()), + item_leaf_owner_modules: Rc::new(im::HashMap::new()), + diagnostics: Rc::new(im::Vector::new()), + }; + let source_indices = HashMap::new(); + let resolved = + resolved_initializer_decl_ref(&graph, &source_indices, &emit_info, &body, None) + .expect("initializer ref must resolve the carried user declaration"); + assert_eq!( + resolved.module, "owner.types", + "carried BoolWitnessClaim declaration must beat variant_to_enum UnifiedTestClaim" + ); + assert_eq!(resolved.name, "BoolWitnessClaim"); + } + + #[test] + fn ambiguous_enum_name_is_not_answered_false() { + use crate::v1_compiler_infer_emit_info::{ + empty_type_summary_index, is_enum_in_summaries, type_summary_index_insert, TypeRepr, + TypeSummary, TypeSummaryQuestion, + }; + let enum_summary = Rc::new(TypeSummary { + name: "SharedName".to_string(), + key: "owner.enums.SharedName".to_string(), + repr: Rc::new(TypeRepr::EnumRepr { unit_only: false }), + field_summaries: crate::v1_rt::rc_empty_map(), + field_type_map: crate::v1_rt::rc_empty_map(), + field_import_surface_names: Rc::new(im::Vector::new()), + variant_name_set: crate::v1_rt::rc_empty_map(), + generic_param_names: Rc::new(im::Vector::new()), + has_fn_fields: false, + }); + let struct_summary = Rc::new(TypeSummary { + name: "SharedName".to_string(), + key: "owner.types.SharedName".to_string(), + repr: Rc::new(TypeRepr::StructRepr), + field_summaries: crate::v1_rt::rc_empty_map(), + field_type_map: crate::v1_rt::rc_empty_map(), + field_import_surface_names: Rc::new(im::Vector::new()), + variant_name_set: crate::v1_rt::rc_empty_map(), + generic_param_names: Rc::new(im::Vector::new()), + has_fn_fields: false, + }); + let index = type_summary_index_insert( + type_summary_index_insert( + empty_type_summary_index(), + "owner.enums.SharedName".to_string(), + "SharedName".to_string(), + enum_summary, + ), + "owner.types.SharedName".to_string(), + "SharedName".to_string(), + struct_summary, + ); + assert!( + matches!( + (*is_enum_in_summaries(index, "SharedName".to_string())).clone(), + TypeSummaryQuestion::QuestionNameAmbiguous { leaf } if leaf == "SharedName" + ), + "disagreement must not collapse to a decided non-enum" + ); + } + + #[test] + fn ambiguous_enum_name_refuses_instead_of_non_enum_emission() { + use crate::v1_compiler_infer_emit_info::{ + empty_type_summary_index, type_summary_index_insert, TypeRepr, TypeSummary, + }; + let enum_summary = Rc::new(TypeSummary { + name: "SharedName".to_string(), + key: "owner.enums.SharedName".to_string(), + repr: Rc::new(TypeRepr::EnumRepr { unit_only: false }), + field_summaries: crate::v1_rt::rc_empty_map(), + field_type_map: crate::v1_rt::rc_empty_map(), + field_import_surface_names: Rc::new(im::Vector::new()), + variant_name_set: crate::v1_rt::rc_empty_map(), + generic_param_names: Rc::new(im::Vector::new()), + has_fn_fields: false, + }); + let struct_summary = Rc::new(TypeSummary { + name: "SharedName".to_string(), + key: "owner.types.SharedName".to_string(), + repr: Rc::new(TypeRepr::StructRepr), + field_summaries: crate::v1_rt::rc_empty_map(), + field_type_map: crate::v1_rt::rc_empty_map(), + field_import_surface_names: Rc::new(im::Vector::new()), + variant_name_set: crate::v1_rt::rc_empty_map(), + generic_param_names: Rc::new(im::Vector::new()), + has_fn_fields: false, + }); + let index = type_summary_index_insert( + type_summary_index_insert( + empty_type_summary_index(), + "owner.enums.SharedName".to_string(), + "SharedName".to_string(), + enum_summary, + ), + "owner.types.SharedName".to_string(), + "SharedName".to_string(), + struct_summary, + ); + let parent = crate::v1_compiler_emit_rust::pattern_parent_enum( + "Arm".to_string(), + None, + "SharedName".to_string(), + index, + ); + let refusal = crate::v1_compiler_emit_rust::rust_ambiguous_type_name_refusal( + "SharedName".to_string(), + ); + assert_eq!( + parent, + Some(refusal), + "an ambiguous enum name must emit the typed refusal, not a non-enum parent" + ); } - None } fn lookup_resolved_type_node(graph: &ResolvedGraph, type_name: &str) -> Option> { @@ -22269,27 +22642,53 @@ fn declared_type_name_from_annotation( } } -fn resolved_decl_ref_from_type_name( - graph: &ResolvedGraph, +fn defining_module_for_inferred_result( + variant_to_enum: &im::HashMap, + type_summaries: &Rc, + type_decls: &Rc, source_indices: &HashMap>, + inferred_node: Option<&Rc>, + name: &str, +) -> Option { + // Type declaration identity first. A user type whose leaf matches a known variant + // (BoolWitnessClaim) must not be stolen by variant_to_enum spelling. + inferred_node + .and_then(|node| { + defining_module_for_type_expr(type_summaries, type_decls, source_indices, node) + }) + .or_else(|| defining_module_for_type_identity(type_summaries, name)) + .or_else(|| defining_module_for_variant(variant_to_enum, name)) +} + +fn resolved_decl_ref_from_type_name( variant_to_enum: &im::HashMap, + type_summaries: &Rc, name: &str, ) -> Result { - let module = defining_module_for_resolved_type(graph, source_indices, variant_to_enum, name) + let module = defining_module_for_type_identity(type_summaries, name) + .or_else(|| defining_module_for_variant(variant_to_enum, name)) .ok_or_else(|| format!("no defining module for resolved type '{}'", name))?; + let stored_name = crate::v1_std_core::qualified_last_segment(name.to_string()); Ok(ResolvedDeclRef { module, - name: name.to_string(), + name: if stored_name.is_empty() { + name.to_string() + } else { + stored_name + }, }) } fn resolved_initializer_decl_ref( graph: &ResolvedGraph, source_indices: &HashMap>, - variant_to_enum: &im::HashMap, + emit_info: &crate::v1_compiler_infer_emit_info::EmitGraphInfo, body: &Rc, type_annotation: Option<&Rc>, ) -> Result { + let variant_to_enum = emit_info.variant_to_enum.as_ref(); + let type_summaries = &emit_info.type_summaries; + let type_decls = &emit_info.type_decl_items; let si = Rc::new(source_indices.clone()); if let ExprData::ExprRecordLit { parent_enum } = &*body.expr_data { if let Some(parent_name) = parent_enum.as_deref() { @@ -22319,18 +22718,13 @@ fn resolved_initializer_decl_ref( variant_name, parent_name )); } - let module = defining_module_for_resolved_type( - graph, - source_indices, - variant_to_enum, - parent_name, - ) - .ok_or_else(|| { - format!( - "no defining module for resolved coproduct '{}'", - parent_name - ) - })?; + let module = + defining_module_for_variant(variant_to_enum, &variant_name).ok_or_else(|| { + format!( + "no defining module for resolved coproduct variant '{}'", + variant_name + ) + })?; return Ok(ResolvedDeclRef { module, name: variant_name, @@ -22359,11 +22753,38 @@ fn resolved_initializer_decl_ref( None => None, }; if let Some(name) = inferred_name { - return resolved_decl_ref_from_type_name(graph, source_indices, variant_to_enum, &name); + let inferred_node = match body.inferred.as_deref() { + Some(InferredNode::Resolved { node }) => Some(node), + _ => None, + }; + if let Some(module) = defining_module_for_inferred_result( + variant_to_enum, + type_summaries, + type_decls, + source_indices, + inferred_node, + &name, + ) { + return Ok(ResolvedDeclRef { + module, + name: crate::v1_std_core::qualified_last_segment(name), + }); + } + return Err(format!("no defining module for resolved type '{}'", name)); } if let Some(ann) = type_annotation { + if let Some(module) = + defining_module_for_type_expr(type_summaries, type_decls, source_indices, ann) + { + let name = declared_type_name_from_annotation(source_indices, ann) + .unwrap_or_else(|| "type".to_string()); + return Ok(ResolvedDeclRef { + module, + name: crate::v1_std_core::qualified_last_segment(name), + }); + } if let Some(name) = declared_type_name_from_annotation(source_indices, ann) { - return resolved_decl_ref_from_type_name(graph, source_indices, variant_to_enum, &name); + return resolved_decl_ref_from_type_name(variant_to_enum, type_summaries, &name); } } Err( @@ -22583,15 +23004,13 @@ pub fn discover_owned_data_decls( // THE ONE READER OF variant_to_enum BUILDS IT, once per group graph, through the builder // emission uses: the resolve no longer carries EmitGraphInfo (v1.compiler.infer_items // ResolvedGraph), and owned-data discovery is the consumer that demands this projection. - let variant_to_enum = v1_compiler_infer::build_emit_graph_info( + let emit_info = v1_compiler_infer::build_emit_graph_info( graph.modules.clone(), graph.item_registry.clone(), - ) - .variant_to_enum - .clone(); + ); for (entry, entry_module, marker_count) in group.entries { let records = - owned_data_decls_for_entry(&graph, &si, &variant_to_enum, &entry, &entry_module)?; + owned_data_decls_for_entry(&graph, &si, &emit_info, &entry, &entry_module)?; if records.len() != marker_count { return Err(format!( "{}: merged-resolve discovery found {} owned unified_claim record(s) but the entry declares {} top-level `data unified_claim_` marker(s)", @@ -36445,12 +36864,18 @@ mod peel_alias_fixpoint_termination { }, ), ); + // No files in this probe: the peel tree is synthetic, module_path is empty. + // file_modules / module_named_imports therefore come from empty_symbol_index, + // the same constructor every other empty SymbolIndex uses. + let empty_index = crate::v1_compiler_infer_env::empty_symbol_index(); let symbol_index = std::rc::Rc::new(crate::v1_compiler_infer_env::SymbolIndex { - entries: crate::v1_rt::rc_empty_map(), + entries: empty_index.entries.clone(), global_bare, - services: crate::v1_rt::rc_empty_map(), - transparent_alias_rep: crate::v1_rt::rc_empty_map(), - type_head_exposures: crate::v1_rt::rc_empty_map(), + services: empty_index.services.clone(), + transparent_alias_rep: empty_index.transparent_alias_rep.clone(), + type_head_exposures: empty_index.type_head_exposures.clone(), + file_modules: empty_index.file_modules.clone(), + module_named_imports: empty_index.module_named_imports.clone(), }); let env = std::rc::Rc::new(crate::v1_compiler_infer_env::TypeEnv { module_path: "".to_string(), diff --git a/src/v1/stage0/src/cli_run/owned_data.rs b/src/v1/stage0/src/cli_run/owned_data.rs index 4a5fc1c67b1..2d9f07f72b6 100644 --- a/src/v1/stage0/src/cli_run/owned_data.rs +++ b/src/v1/stage0/src/cli_run/owned_data.rs @@ -96,20 +96,15 @@ use serde::Serialize; pub(crate) fn owned_data_initializer_from_body( graph: &ResolvedGraph, source_indices: &HashMap>, - variant_to_enum: &im::HashMap, + emit_info: &crate::v1_compiler_infer_emit_info::EmitGraphInfo, entry_path: &str, decl_name: &str, body: &Rc, type_annotation: Option<&Rc>, ) -> Result { - let resolved_initializer = resolved_initializer_decl_ref( - graph, - source_indices, - variant_to_enum, - body, - type_annotation, - ) - .map_err(|e| format!("{entry_path}: owned data '{decl_name}': {e}"))?; + let resolved_initializer = + resolved_initializer_decl_ref(graph, source_indices, emit_info, body, type_annotation) + .map_err(|e| format!("{entry_path}: owned data '{decl_name}': {e}"))?; if is_resolved_bool_witness_claim(&resolved_initializer) { let (witness_entry, witness_function) = extract_bool_witness_transport(body, source_indices); @@ -135,7 +130,7 @@ pub(crate) fn owned_data_initializer_from_body( pub fn owned_data_decls_for_entry( graph: &ResolvedGraph, source_indices: &HashMap>, - variant_to_enum: &im::HashMap, + emit_info: &crate::v1_compiler_infer_emit_info::EmitGraphInfo, entry_path: &str, entry_module: &str, ) -> Result, String> { @@ -195,7 +190,7 @@ pub fn owned_data_decls_for_entry( let initializer = owned_data_initializer_from_body( graph, source_indices, - variant_to_enum, + emit_info, entry_path, &decl_name, body, diff --git a/src/v1/stage0/src/compiler_tests.rs b/src/v1/stage0/src/compiler_tests.rs index 234e3dac8a2..7dd37e0eceb 100644 --- a/src/v1/stage0/src/compiler_tests.rs +++ b/src/v1/stage0/src/compiler_tests.rs @@ -4418,10 +4418,25 @@ mod compiler_tests { ) ); assert!( - crate::v1_compiler_emit_rust::is_grounded_coproduct_native_alias( + crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias( + "v2.std.diagnostic".to_string(), "Diagnostics".to_string() ) ); + // The host option is a DECLARATION, not a name: the kernel optional's declaration is it, and a + // coproduct another module declares as Optional is not. + assert!( + crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias( + "std.optional".to_string(), + "Optional".to_string() + ) + ); + assert!( + !crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias( + "gunbc.instruments.native_emission_controls_optional_collision".to_string(), + "Optional".to_string() + ) + ); let empty_shared = std::rc::Rc::new(im::OrdSet::new()); assert_eq!( crate::v1_compiler_emit_rust::render_rust_diagnostics_carrier_applied( @@ -5439,7 +5454,7 @@ mod compiler_tests { // A QUALIFIED REFERENCE IS NOT DECIDED BY THE LOCAL DECLARER. hom.local declares its own Slot // and ALSO names no.such.module.Slot, which resolve cannot bind, so the reference reaches the // emitter unstamped while two modules declare Slot. The referencing-module arm - // (v1.compiler.infer_emit_info type_decl_referencing_module_declarer) would pick the LOCAL Slot: + // (v1.compiler.infer_emit_info type_decl_occurrence_binding) would pick the LOCAL Slot: // the wrong-declarer class itself. It is admitted only for a bare spelling, so this refuses. // THE CONTROL is the same module without the second declarer: the spelling names a sole // declarer, and nothing refuses. @@ -5474,6 +5489,154 @@ mod compiler_tests { ); } + // A SAME-LEAF TYPE ANYWHERE MUST NOT CHANGE ANOTHER MODULE'S EMISSION. hom.user returns the kernel + // optional's Absent; hom.edge declares an unrelated enum that also has an Absent variant. With the + // leaf-keyed type summaries, adding hom.coll (a coproduct it declares as Optional) replaced the + // kernel Optional's summary, so Absent stopped being an Optional variant and hom.user emitted + // Rc::new(Lookup::Absent) where it had emitted None. Keyed by declaration, both summaries stand: + // hom.user's file is byte-identical with and without hom.coll, and its Absent is the host None. + #[test] + fn same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged() { + use crate::v1_compiler_compile::SourceFile; + let src = |path: &str, content: &str| { + std::rc::Rc::new(SourceFile { + path: path.to_string(), + content: content.to_string(), + }) + }; + let optional = || { + src( + "fixtures/same_leaf_optional/optional.dag", + "module std.optional\n\ntype Optional\n = Present { value: T }\n | Absent\n", + ) + }; + let edge = || { + src( + "fixtures/same_leaf_optional/edge.dag", + "module hom.edge\n\ntype Lookup\n = Found { at: Int }\n | Absent\n", + ) + }; + let user = || { + src("fixtures/same_leaf_optional/user.dag", "module hom.user\nimport std.optional { Optional, Present, Absent }\n\nfn nothing_here(x: Int) -> Optional {\n Absent\n}\n") + }; + let coll = || { + src("fixtures/same_leaf_optional/coll.dag", "module hom.coll\n\ntype Optional\n = CollisionWrapped { value: Int }\n | CollisionEmpty\n") + }; + let emitted_user = |sources: Vec>| -> String { + let result = crate::v1_compiler_compile::compile_sources( + std::rc::Rc::new(sources.into()), + crate::v1_compiler_artifact::RenderTarget::Rust, + ); + result + .files + .iter() + .find(|f| f.path.contains("hom_user")) + .map(|f| f.content.clone()) + .unwrap_or_default() + }; + let without = emitted_user(vec![optional(), edge(), user()]); + let with = emitted_user(vec![optional(), edge(), user(), coll()]); + assert!( + without.contains("None") && !without.contains("Lookup::Absent"), + "the control: hom.user's Absent is the host None:\n{without}" + ); + assert_eq!( + with, without, + "adding a same-leaf Optional elsewhere changed hom.user's emission" + ); + } + + // AN UNSTAMPED BARE `Optional` FOLLOWS THE TYPECHECKER'S lookup_binding ORDER: own file, then + // the file's named import (followed through re-exports), then the kernel + // (v1.compiler.infer_env bare_occurrence_binding). The member references of a coproduct body reach + // the emitter from the type environment's copy with no Node.declaration, so the census route is + // the emitter's own decision. THE RED is the importer: with the kernel ahead of the named import + // (the order direct_import_export_precedence_note states) its payload routes kernel_mint to + // std.optional, measured on gunbc#13454 at 57551c4b. The control keeps a module that names + // Optional without importing it on the kernel arm. + #[test] + fn unstamped_bare_optional_follows_the_lookup_binding_order() { + use crate::v1_compiler_compile::SourceFile; + let sources = vec![ + std::rc::Rc::new(SourceFile { path: "fixtures/kernel_shadow/optional.dag".to_string(), content: "module std.optional\n\ntype Optional\n = Present { value: T }\n | Absent\n".to_string() }), + std::rc::Rc::new(SourceFile { path: "fixtures/kernel_shadow/collision.dag".to_string(), content: "module hom.collision\n\ntype Optional\n = CollisionWrapped { value: Int }\n | CollisionEmpty\n".to_string() }), + std::rc::Rc::new(SourceFile { path: "fixtures/kernel_shadow/importer.dag".to_string(), content: "module hom.importer\n\nimport hom.collision { Optional }\n\ntype HeldChoice\n = HeldOptional { held: Optional }\n | HeldNothing\n".to_string() }), + std::rc::Rc::new(SourceFile { path: "fixtures/kernel_shadow/plain.dag".to_string(), content: "module hom.plain\n\ntype PlainChoice\n = PlainHeld { held: Optional }\n | PlainNothing\n".to_string() }), + std::rc::Rc::new(SourceFile { path: "fixtures/kernel_shadow/user.dag".to_string(), content: "module hom.user\n\nimport hom.importer { HeldChoice }\nimport hom.plain { PlainChoice }\n\nfn pick(h: HeldChoice, p: PlainChoice) -> Int {\n 1\n}\n".to_string() }), + ]; + let receipt = crate::v1_tests_claim_carrier_realization_census::typed_census_from_sources( + std::rc::Rc::new(sources.into()), + ); + assert!(!receipt.starts_with("REFUSED"), "{receipt}"); + let routes = |enclosing: &str| -> Vec { + receipt + .lines() + .skip(1) + .map(|l| l.split('\t').collect::>()) + .filter(|c| c[1] == enclosing && c[2] == "declaration_field" && c[3] == "Optional") + .map(|c| c[13].to_string()) + .collect() + }; + let held = routes("HeldChoice"); + assert!( + !held.is_empty() + && held + .iter() + .all(|r| r == "referencing_module_import:Resolved:hom.collision.Optional"), + "the imported Optional must route to the import, never the kernel mint:\n{receipt}" + ); + let plain = routes("PlainChoice"); + assert!( + !plain.is_empty() + && plain + .iter() + .all(|r| r == "kernel_mint:Resolved:std.optional.Optional"), + "an unimported Optional is the kernel's:\n{receipt}" + ); + assert!(!receipt.contains("LeafAmbiguous:Optional"), "{receipt}"); + } + + // A COPRODUCT NAMED Optional EMITS AS ITS OWN ENUM. still-raven-321's fixture, + // fixtures/native_emission_controls_optional_collision.dag, is a non-kernel declaration that shares + // the kernel mint's leaf. Host-Option is decided by declaration (v1.compiler.emit_rust + // declaration_owns_host_option over gunbc.structural_realization_bindings kernel_mint_declaration_rows), + // so its positions name its own enum. THE RED is the leaf rule this replaced: every position rendered + // as Option<..> and the variants were never emitted (E0425 cannot find CollisionWrapped). The fixture + // lives outside the source roots, because a second Optional in the accepted corpus is a leaf-name fork, + // so it is compiled here, from its file, beside a kernel std.optional. Its one import line names a + // kernel type and is dropped so the pair compiles standalone. + #[test] + fn a_coproduct_named_optional_emits_as_its_own_enum() { + use crate::v1_compiler_compile::SourceFile; + let collision = read_dag("fixtures/native_emission_controls_optional_collision.dag") + .replace("import std.types { Int }\n", ""); + let sources = vec![ + std::rc::Rc::new(SourceFile { path: "fixtures/kernel_shadow/optional.dag".to_string(), content: "module std.optional\n\ntype Optional\n = Present { value: T }\n | Absent\n".to_string() }), + std::rc::Rc::new(SourceFile { path: "fixtures/native_emission_controls_optional_collision.dag".to_string(), content: collision }), + ]; + let result = crate::v1_compiler_compile::compile_sources( + std::rc::Rc::new(sources.into()), + crate::v1_compiler_artifact::RenderTarget::Rust, + ); + let emitted = result + .files + .iter() + .find(|f| { + f.path + .contains("native_emission_controls_optional_collision") + }) + .map(|f| f.content.clone()) + .unwrap_or_default(); + assert!( + emitted.contains("pub enum Optional") && emitted.contains("CollisionWrapped"), + "the collision coproduct must emit as its own enum:\n{emitted}" + ); + assert!( + !emitted.contains("Option<") && !emitted.contains("compile_error!"), + "no position of the collision coproduct may realize as the host Option:\n{emitted}" + ); + } + // A REPEATED TYPE PARAMETER IN ONE HEADER REFUSES, LOCATED, AND SAYS WHICH NAME. The refusal // predates this row. Its message once blamed a value parameter and called a type a fn, so the // row asserts the NAME and the OWNER, not merely that some diagnostic fired. The control header diff --git a/src/v1/stage0/src/gunbc_rust_source_type_bindings.rs b/src/v1/stage0/src/gunbc_rust_source_type_bindings.rs index 2627adc50ca..98256d0f36e 100644 --- a/src/v1/stage0/src/gunbc_rust_source_type_bindings.rs +++ b/src/v1/stage0/src/gunbc_rust_source_type_bindings.rs @@ -135,7 +135,7 @@ pub fn checkpoint_row_migration_rows() -> Rc>> { }), Rc::new(CheckpointRowMigration { dag_name: "String".to_string(), disposition: Rc::new(CheckpointRowDisposition::ProvenUniqueKernelBinding { - proof: "The kernel string_type is minted by v1.compiler.types for every string literal and carries no declaration; both .dag declarations of the spelling (v2.std.text, std.string_type) are gated structural by v1.compiler.coercion structural_declaration_modules_for and never reach this row. THE VERDICT STANDS AND ITS ORIGINAL ARGUMENT WAS EXACTLY INVERTED, corrected here rather than softened because the inverted form would justify the wrong things if reused. It read: the bare spelling cannot be captured because the only import that could shadow it binds the SAME token, so in a module importing v2.std.text String every `String` reference IS the text carrier and the kernel spelling is unreachable there. The opposite is true. KERNEL NAMES ARE NEVER OVERRIDDEN BY IMPORTS (v1.compiler.infer direct_import_export_precedence_note, overlay_skips_kernel_name), so in such a module the import does not shadow at all and a bare `String` is ALWAYS the kernel -- the spelling the old argument called unreachable is the only one you reach. Three routes exist and all three are sound for this row: a bare reference in an importing module resolves to the kernel and IS this row's binding; a bare reference INSIDE v2.std.text resolves LOCALLY (locals beat kernel) and is gated structural, never reaching the row; and a QUALIFIED v2.std.text.String resolves through the alias to the dotted name std.algebra.FreeMonoid, which matches no bare row. Symbol was captured precisely because its token differed from its spelling, and that clause survives unchanged. ESTABLISHED BY EXECUTION, not by reading precedence -- AND THE SUBJECT NAMED HERE IS CORRECTED: this sentence previously said the census was run over A FIXTURE MODULE importing both v2.std.text String and v2.std.node Node. IT WAS NOT. The receipts carry no fixture rows at all; the subjects were LIVE CORPUS MODULES, and naming a subject that was not run is the same citation defect this row exists to correct. What v1.tests.claim.carrier_realization_census actually reports: in std.algebra, a module that imports the spelling, a bare String carries the kernel identity at declaration_field AND at fn_signature_param; inside v2.std.text the same spelling carries its own declaring module and diverges with exact identity, which is route 2 executed rather than argued; and v2.std.node Node carries its real declaring module at both position kinds as the positive control. RE-DERIVATION IS POSITION-KIND SENSITIVE AND THE OBVIOUS INSTRUCTION IS A TRAP. Running that census over a closure re-derives routes 1 and 2 soundly. It does NOT re-derive route 3: at fn_signature_param the census resolves a QUALIFIED v2.std.text.String through the alias onto the alias declaration's own name, which is the spelling String, and attributes it to -- confidently naming the very carrier the qualification was written to move away from. That is measured by vivid-deer-102 and filed as recurring failure mode alias_resolution_collides_with_kernel_spelling (gunbc#9939); the same instrument is correct for qualified aliases at declaration_field. ROUTE 3 THEREFORE RESTS ON STRUCTURAL RESOLUTION PLUS A RUSTC MEASUREMENT -- the emitted crate carries an E0308 on the bare arm and not on the qualified one -- and explicitly NOT on this census, which cannot answer at that position. The instrument is named rather than its rows transcribed (DESIGN section 6). SINCE gunbc#12760 THE KERNEL HOST TEXT HAS A DECLARATION: v2.std.node String, opaque, with its own exact row above (RustStdString). So the kernel spelling now has one declaration, and this bare row and that exact row render the same carrier, std::string::String; the uniqueness this row proves is unchanged.".to_string(), + proof: "The kernel string_type is minted by v1.compiler.types for every string literal and carries no declaration; both .dag declarations of the spelling (v2.std.text, std.string_type) are gated structural by v1.compiler.coercion structural_declaration_modules_for and never reach this row. THE VERDICT STANDS AND ITS ORIGINAL ARGUMENT WAS EXACTLY INVERTED, corrected here rather than softened because the inverted form would justify the wrong things if reused. It read: the bare spelling cannot be captured because the only import that could shadow it binds the SAME token, so in a module importing v2.std.text String every `String` reference IS the text carrier and the kernel spelling is unreachable there. The opposite is true. KERNEL NAMES ARE NEVER OVERRIDDEN BY IMPORTS (v1.compiler.infer direct_import_export_precedence_note; v1.compiler.infer_env overlay_skips_kernel_name), so in such a module the import does not shadow at all and a bare `String` is ALWAYS the kernel -- the spelling the old argument called unreachable is the only one you reach. Three routes exist and all three are sound for this row: a bare reference in an importing module resolves to the kernel and IS this row's binding; a bare reference INSIDE v2.std.text resolves LOCALLY (locals beat kernel) and is gated structural, never reaching the row; and a QUALIFIED v2.std.text.String resolves through the alias to the dotted name std.algebra.FreeMonoid, which matches no bare row. Symbol was captured precisely because its token differed from its spelling, and that clause survives unchanged. ESTABLISHED BY EXECUTION, not by reading precedence -- AND THE SUBJECT NAMED HERE IS CORRECTED: this sentence previously said the census was run over A FIXTURE MODULE importing both v2.std.text String and v2.std.node Node. IT WAS NOT. The receipts carry no fixture rows at all; the subjects were LIVE CORPUS MODULES, and naming a subject that was not run is the same citation defect this row exists to correct. What v1.tests.claim.carrier_realization_census actually reports: in std.algebra, a module that imports the spelling, a bare String carries the kernel identity at declaration_field AND at fn_signature_param; inside v2.std.text the same spelling carries its own declaring module and diverges with exact identity, which is route 2 executed rather than argued; and v2.std.node Node carries its real declaring module at both position kinds as the positive control. RE-DERIVATION IS POSITION-KIND SENSITIVE AND THE OBVIOUS INSTRUCTION IS A TRAP. Running that census over a closure re-derives routes 1 and 2 soundly. It does NOT re-derive route 3: at fn_signature_param the census resolves a QUALIFIED v2.std.text.String through the alias onto the alias declaration's own name, which is the spelling String, and attributes it to -- confidently naming the very carrier the qualification was written to move away from. That is measured by vivid-deer-102 and filed as recurring failure mode alias_resolution_collides_with_kernel_spelling (gunbc#9939); the same instrument is correct for qualified aliases at declaration_field. ROUTE 3 THEREFORE RESTS ON STRUCTURAL RESOLUTION PLUS A RUSTC MEASUREMENT -- the emitted crate carries an E0308 on the bare arm and not on the qualified one -- and explicitly NOT on this census, which cannot answer at that position. The instrument is named rather than its rows transcribed (DESIGN section 6). SINCE gunbc#12760 THE KERNEL HOST TEXT HAS A DECLARATION: v2.std.node String, opaque, with its own exact row above (RustStdString). So the kernel spelling now has one declaration, and this bare row and that exact row render the same carrier, std::string::String; the uniqueness this row proves is unchanged.".to_string(), }), }), Rc::new(CheckpointRowMigration { dag_name: "Int".to_string(), diff --git a/src/v1/stage0/src/v1_compiler_compiler_tests_rust.rs b/src/v1/stage0/src/v1_compiler_compiler_tests_rust.rs index 4396c6b6dcf..299e40a3b8a 100644 --- a/src/v1/stage0/src/v1_compiler_compiler_tests_rust.rs +++ b/src/v1/stage0/src/v1_compiler_compiler_tests_rust.rs @@ -152,8 +152,20 @@ pub fn ct_unbound_reference_to_a_twice_declared_leaf_refuses_test() -> String { v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" // A REFERENCE NO ARM RESOLVES REFUSES, AND SAYS WHICH LEAF. hom.third names Slot through a\n".to_string(), " // qualifier no module answers to, so resolve binds nothing and stamps nothing; two modules\n".to_string()), " // declare Slot, so the spelling does not decide either. The leaf-keyed index took whichever Slot\n".to_string()), " // was folded last. THE CONTROL is the same reference in a closure with ONE Slot: the spelling\n".to_string()), " // then names a sole declarer and the holder emits with that declaration's bound.\n".to_string()), " #[test]\n".to_string()), " fn unbound_reference_to_a_twice_declared_leaf_refuses() {\n".to_string()), " use crate::v1_compiler_compile::SourceFile;\n".to_string()), " let wide = || std::rc::Rc::new(SourceFile { path: \"fixtures/same_leaf_refusal/wide.dag\".to_string(), content: \"module hom.wide\\n\\ntype Inner {\\n value: C\\n}\\n\\ntype Slot {\\n first: Inner\\n second: Inner\\n}\\n\".to_string() });\n".to_string()), " let narrow = || std::rc::Rc::new(SourceFile { path: \"fixtures/same_leaf_refusal/narrow.dag\".to_string(), content: \"module hom.narrow\\n\\ntype Slot {\\n held: T\\n}\\n\".to_string() });\n".to_string()), " let third = || std::rc::Rc::new(SourceFile { path: \"fixtures/same_leaf_refusal/third.dag\".to_string(), content: \"module hom.third\\n\\ntype Odd {\\n slot: no.such.module.Slot\\n}\\n\".to_string() });\n".to_string()), " let emitted = |sources: Vec>| -> String {\n".to_string()), " let result = crate::v1_compiler_compile::compile_sources(std::rc::Rc::new(sources.into()), crate::v1_compiler_artifact::RenderTarget::Rust);\n".to_string()), " result.files.iter().find(|f| f.path.contains(\"hom_third\")).map(|f| f.content.clone()).unwrap_or_default()\n".to_string()), " };\n".to_string()), " let red = emitted(vec![wide(), narrow(), third()]);\n".to_string()), " assert!(red.contains(\"compile_error!\") && red.contains(\"item 'Odd' references type 'Slot', which more than one module of this closure declares\"), \"two declarers and no identity must refuse, naming the leaf:\\n{red}\");\n".to_string()), " let control = emitted(vec![narrow(), third()]);\n".to_string()), " assert!(control.contains(\"pub struct Odd\") && !control.contains(\"more than one module of this closure declares\"), \"a sole declarer resolves by spelling:\\n{control}\");\n".to_string()), " }\n\n".to_string()) } +pub fn ct_a_coproduct_named_optional_emits_as_its_own_enum_test() -> String { + Rc::new(vec![" // A COPRODUCT NAMED Optional EMITS AS ITS OWN ENUM. still-raven-321's fixture,\n".to_string(), " // fixtures/native_emission_controls_optional_collision.dag, is a non-kernel declaration that shares\n".to_string(), " // the kernel mint's leaf. Host-Option is decided by declaration (v1.compiler.emit_rust\n".to_string(), " // declaration_owns_host_option over gunbc.structural_realization_bindings kernel_mint_declaration_rows),\n".to_string(), " // so its positions name its own enum. THE RED is the leaf rule this replaced: every position rendered\n".to_string(), " // as Option<..> and the variants were never emitted (E0425 cannot find CollisionWrapped). The fixture\n".to_string(), " // lives outside the source roots, because a second Optional in the accepted corpus is a leaf-name fork,\n".to_string(), " // so it is compiled here, from its file, beside a kernel std.optional. Its one import line names a\n".to_string(), " // kernel type and is dropped so the pair compiles standalone.\n".to_string(), " #[test]\n".to_string(), " fn a_coproduct_named_optional_emits_as_its_own_enum() {\n".to_string(), " use crate::v1_compiler_compile::SourceFile;\n".to_string(), " let collision = read_dag(\"fixtures/native_emission_controls_optional_collision.dag\").replace(\"import std.types { Int }\\n\", \"\");\n".to_string(), " let sources = vec![\n".to_string(), " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/optional.dag\".to_string(), content: \"module std.optional\\n\\ntype Optional\\n = Present { value: T }\\n | Absent\\n\".to_string() }),\n".to_string(), " std::rc::Rc::new(SourceFile { path: \"fixtures/native_emission_controls_optional_collision.dag\".to_string(), content: collision }),\n".to_string(), " ];\n".to_string(), " let result = crate::v1_compiler_compile::compile_sources(std::rc::Rc::new(sources.into()), crate::v1_compiler_artifact::RenderTarget::Rust);\n".to_string(), " let emitted = result.files.iter().find(|f| f.path.contains(\"native_emission_controls_optional_collision\")).map(|f| f.content.clone()).unwrap_or_default();\n".to_string(), " assert!(emitted.contains(\"pub enum Optional\") && emitted.contains(\"CollisionWrapped\"), \"the collision coproduct must emit as its own enum:\\n{emitted}\");\n".to_string(), " assert!(!emitted.contains(\"Option<\") && !emitted.contains(\"compile_error!\"), \"no position of the collision coproduct may realize as the host Option:\\n{emitted}\");\n".to_string(), " }\n".to_string(), "\n".to_string()]).join(&"".to_string()) +} + +pub fn ct_unstamped_bare_optional_follows_the_lookup_binding_order_test() -> String { + Rc::new(vec![" // AN UNSTAMPED BARE `Optional` FOLLOWS THE TYPECHECKER'S lookup_binding ORDER: own file, then\n".to_string(), " // the file's named import (followed through re-exports), then the kernel\n".to_string(), " // (v1.compiler.infer_env bare_occurrence_binding). The member references of a coproduct body reach\n".to_string(), " // the emitter from the type environment's copy with no Node.declaration, so the census route is\n".to_string(), " // the emitter's own decision. THE RED is the importer: with the kernel ahead of the named import\n".to_string(), " // (the order direct_import_export_precedence_note states) its payload routes kernel_mint to\n".to_string(), " // std.optional, measured on gunbc#13454 at 57551c4b. The control keeps a module that names\n".to_string(), " // Optional without importing it on the kernel arm.\n".to_string(), " #[test]\n".to_string(), " fn unstamped_bare_optional_follows_the_lookup_binding_order() {\n".to_string(), " use crate::v1_compiler_compile::SourceFile;\n".to_string(), " let sources = vec![\n".to_string(), " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/optional.dag\".to_string(), content: \"module std.optional\\n\\ntype Optional\\n = Present { value: T }\\n | Absent\\n\".to_string() }),\n".to_string(), " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/collision.dag\".to_string(), content: \"module hom.collision\\n\\ntype Optional\\n = CollisionWrapped { value: Int }\\n | CollisionEmpty\\n\".to_string() }),\n".to_string(), " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/importer.dag\".to_string(), content: \"module hom.importer\\n\\nimport hom.collision { Optional }\\n\\ntype HeldChoice\\n = HeldOptional { held: Optional }\\n | HeldNothing\\n\".to_string() }),\n".to_string(), " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/plain.dag\".to_string(), content: \"module hom.plain\\n\\ntype PlainChoice\\n = PlainHeld { held: Optional }\\n | PlainNothing\\n\".to_string() }),\n".to_string(), " std::rc::Rc::new(SourceFile { path: \"fixtures/kernel_shadow/user.dag\".to_string(), content: \"module hom.user\\n\\nimport hom.importer { HeldChoice }\\nimport hom.plain { PlainChoice }\\n\\nfn pick(h: HeldChoice, p: PlainChoice) -> Int {\\n 1\\n}\\n\".to_string() }),\n".to_string(), " ];\n".to_string(), " let receipt = crate::v1_tests_claim_carrier_realization_census::typed_census_from_sources(std::rc::Rc::new(sources.into()));\n".to_string(), " assert!(!receipt.starts_with(\"REFUSED\"), \"{receipt}\");\n".to_string(), " let routes = |enclosing: &str| -> Vec {\n".to_string(), " receipt.lines().skip(1).map(|l| l.split('\\t').collect::>())\n".to_string(), " .filter(|c| c[1] == enclosing && c[2] == \"declaration_field\" && c[3] == \"Optional\")\n".to_string(), " .map(|c| c[13].to_string()).collect()\n".to_string(), " };\n".to_string(), " let held = routes(\"HeldChoice\");\n".to_string(), " assert!(!held.is_empty() && held.iter().all(|r| r == \"referencing_module_import:Resolved:hom.collision.Optional\"), \"the imported Optional must route to the import, never the kernel mint:\\n{receipt}\");\n".to_string(), " let plain = routes(\"PlainChoice\");\n".to_string(), " assert!(!plain.is_empty() && plain.iter().all(|r| r == \"kernel_mint:Resolved:std.optional.Optional\"), \"an unimported Optional is the kernel's:\\n{receipt}\");\n".to_string(), " assert!(!receipt.contains(\"LeafAmbiguous:Optional\"), \"{receipt}\");\n".to_string(), " }\n".to_string(), "\n".to_string()]).join(&"".to_string()) +} + +pub fn ct_same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged_test() -> String { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" // A SAME-LEAF TYPE ANYWHERE MUST NOT CHANGE ANOTHER MODULE'S EMISSION. hom.user returns the kernel\n".to_string(), " // optional's Absent; hom.edge declares an unrelated enum that also has an Absent variant. With the\n".to_string()), " // leaf-keyed type summaries, adding hom.coll (a coproduct it declares as Optional) replaced the\n".to_string()), " // kernel Optional's summary, so Absent stopped being an Optional variant and hom.user emitted\n".to_string()), " // Rc::new(Lookup::Absent) where it had emitted None. Keyed by declaration, both summaries stand:\n".to_string()), " // hom.user's file is byte-identical with and without hom.coll, and its Absent is the host None.\n".to_string()), " #[test]\n".to_string()), " fn same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged() {\n".to_string()), " use crate::v1_compiler_compile::SourceFile;\n".to_string()), " let src = |path: &str, content: &str| std::rc::Rc::new(SourceFile { path: path.to_string(), content: content.to_string() });\n".to_string()), " let optional = || src(\"fixtures/same_leaf_optional/optional.dag\", \"module std.optional\\n\\ntype Optional\\n = Present { value: T }\\n | Absent\\n\");\n".to_string()), " let edge = || src(\"fixtures/same_leaf_optional/edge.dag\", \"module hom.edge\\n\\ntype Lookup\\n = Found { at: Int }\\n | Absent\\n\");\n".to_string()), " let user = || src(\"fixtures/same_leaf_optional/user.dag\", \"module hom.user\\nimport std.optional { Optional, Present, Absent }\\n\\nfn nothing_here(x: Int) -> Optional {\\n Absent\\n}\\n\");\n".to_string()), " let coll = || src(\"fixtures/same_leaf_optional/coll.dag\", \"module hom.coll\\n\\ntype Optional\\n = CollisionWrapped { value: Int }\\n | CollisionEmpty\\n\");\n".to_string()), " let emitted_user = |sources: Vec>| -> String {\n".to_string()), " let result = crate::v1_compiler_compile::compile_sources(std::rc::Rc::new(sources.into()), crate::v1_compiler_artifact::RenderTarget::Rust);\n".to_string()), " result.files.iter().find(|f| f.path.contains(\"hom_user\")).map(|f| f.content.clone()).unwrap_or_default()\n".to_string()), " };\n".to_string()), " let without = emitted_user(vec![optional(), edge(), user()]);\n".to_string()), " let with = emitted_user(vec![optional(), edge(), user(), coll()]);\n".to_string()), " assert!(without.contains(\"None\") && !without.contains(\"Lookup::Absent\"), \"the control: hom.user's Absent is the host None:\\n{without}\");\n".to_string()), " assert_eq!(with, without, \"adding a same-leaf Optional elsewhere changed hom.user's emission\");\n".to_string()), " }\n".to_string()), "\n".to_string()) +} + pub fn ct_qualified_reference_is_not_decided_by_the_local_declarer_test() -> String { - v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" // A QUALIFIED REFERENCE IS NOT DECIDED BY THE LOCAL DECLARER. hom.local declares its own Slot\n".to_string(), " // and ALSO names no.such.module.Slot, which resolve cannot bind, so the reference reaches the\n".to_string()), " // emitter unstamped while two modules declare Slot. The referencing-module arm\n".to_string()), " // (v1.compiler.infer_emit_info type_decl_referencing_module_declarer) would pick the LOCAL Slot:\n".to_string()), " // the wrong-declarer class itself. It is admitted only for a bare spelling, so this refuses.\n".to_string()), " // THE CONTROL is the same module without the second declarer: the spelling names a sole\n".to_string()), " // declarer, and nothing refuses.\n".to_string()), " #[test]\n".to_string()), " fn qualified_reference_is_not_decided_by_the_local_declarer() {\n".to_string()), " use crate::v1_compiler_compile::SourceFile;\n".to_string()), " let wide = || std::rc::Rc::new(SourceFile { path: \"fixtures/same_leaf_qualified/wide.dag\".to_string(), content: \"module hom.wide\\n\\ntype Inner {\\n value: C\\n}\\n\\ntype Slot {\\n first: Inner\\n second: Inner\\n}\\n\".to_string() });\n".to_string()), " let local = || std::rc::Rc::new(SourceFile { path: \"fixtures/same_leaf_qualified/local.dag\".to_string(), content: \"module hom.local\\n\\ntype Slot {\\n held: T\\n}\\n\\ntype Odd {\\n slot: no.such.module.Slot\\n}\\n\".to_string() });\n".to_string()), " let emitted = |sources: Vec>| -> String {\n".to_string()), " let result = crate::v1_compiler_compile::compile_sources(std::rc::Rc::new(sources.into()), crate::v1_compiler_artifact::RenderTarget::Rust);\n".to_string()), " result.files.iter().find(|f| f.path.contains(\"hom_local\")).map(|f| f.content.clone()).unwrap_or_default()\n".to_string()), " };\n".to_string()), " let red = emitted(vec![wide(), local()]);\n".to_string()), " assert!(red.contains(\"compile_error!\") && red.contains(\"item 'Odd' references type 'Slot', which more than one module of this closure declares\"), \"a qualified unstamped reference must refuse, not take the local Slot:\\n{red}\");\n".to_string()), " let control = emitted(vec![local()]);\n".to_string()), " assert!(control.contains(\"pub struct Odd\") && !control.contains(\"more than one module of this closure declares\"), \"a sole declarer resolves by spelling:\\n{control}\");\n".to_string()), " }\n\n".to_string()) + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" // A QUALIFIED REFERENCE IS NOT DECIDED BY THE LOCAL DECLARER. hom.local declares its own Slot\n".to_string(), " // and ALSO names no.such.module.Slot, which resolve cannot bind, so the reference reaches the\n".to_string()), " // emitter unstamped while two modules declare Slot. The referencing-module arm\n".to_string()), " // (v1.compiler.infer_emit_info type_decl_occurrence_binding) would pick the LOCAL Slot:\n".to_string()), " // the wrong-declarer class itself. It is admitted only for a bare spelling, so this refuses.\n".to_string()), " // THE CONTROL is the same module without the second declarer: the spelling names a sole\n".to_string()), " // declarer, and nothing refuses.\n".to_string()), " #[test]\n".to_string()), " fn qualified_reference_is_not_decided_by_the_local_declarer() {\n".to_string()), " use crate::v1_compiler_compile::SourceFile;\n".to_string()), " let wide = || std::rc::Rc::new(SourceFile { path: \"fixtures/same_leaf_qualified/wide.dag\".to_string(), content: \"module hom.wide\\n\\ntype Inner {\\n value: C\\n}\\n\\ntype Slot {\\n first: Inner\\n second: Inner\\n}\\n\".to_string() });\n".to_string()), " let local = || std::rc::Rc::new(SourceFile { path: \"fixtures/same_leaf_qualified/local.dag\".to_string(), content: \"module hom.local\\n\\ntype Slot {\\n held: T\\n}\\n\\ntype Odd {\\n slot: no.such.module.Slot\\n}\\n\".to_string() });\n".to_string()), " let emitted = |sources: Vec>| -> String {\n".to_string()), " let result = crate::v1_compiler_compile::compile_sources(std::rc::Rc::new(sources.into()), crate::v1_compiler_artifact::RenderTarget::Rust);\n".to_string()), " result.files.iter().find(|f| f.path.contains(\"hom_local\")).map(|f| f.content.clone()).unwrap_or_default()\n".to_string()), " };\n".to_string()), " let red = emitted(vec![wide(), local()]);\n".to_string()), " assert!(red.contains(\"compile_error!\") && red.contains(\"item 'Odd' references type 'Slot', which more than one module of this closure declares\"), \"a qualified unstamped reference must refuse, not take the local Slot:\\n{red}\");\n".to_string()), " let control = emitted(vec![local()]);\n".to_string()), " assert!(control.contains(\"pub struct Odd\") && !control.contains(\"more than one module of this closure declares\"), \"a sole declarer resolves by spelling:\\n{control}\");\n".to_string()), " }\n\n".to_string()) } pub fn ct_duplicate_type_parameter_refuses_test() -> String { @@ -174,7 +186,7 @@ pub fn ct_coercion_tests() -> String { } __result }); - v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" // =========================================================================\n".to_string(), " // Coercion registry tests (auto-generated from data declarations)\n".to_string()), " // =========================================================================\n\n".to_string()), test_fns.clone().join(&"\n".to_string())), ct_rust_btree_set_ord_eligibility_test()), ct_unresolved_variant_pattern_refuses_test()), ct_diagnostics_carrier_grounding_test()), ct_std_nat_realization_agreement_test()), ct_std_nat_operators_refuse_overflow_test()), ct_render_rust_applied_type_qualified_base_test()), ct_measure_unit_variant_exact_one_test()), ct_renderer_hop_identity_keying_test()), ct_generic_param_declines_fail_closed_unwrap_test()), ct_witness_carrier_declines_non_witness_expected_type_test()), ct_kernel_identity_single_authority_test()), ct_type_reference_identity_split_test()), ct_declaration_field_reference_identity_test()), ct_same_leaf_type_declarations_emit_by_identity_test()), ct_unbound_reference_to_a_twice_declared_leaf_refuses_test()), ct_qualified_reference_is_not_decided_by_the_local_declarer_test()), ct_duplicate_type_parameter_refuses_test()), ct_resource_item_is_not_a_type_item_test()) + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" // =========================================================================\n".to_string(), " // Coercion registry tests (auto-generated from data declarations)\n".to_string()), " // =========================================================================\n\n".to_string()), test_fns.clone().join(&"\n".to_string())), ct_rust_btree_set_ord_eligibility_test()), ct_unresolved_variant_pattern_refuses_test()), ct_diagnostics_carrier_grounding_test()), ct_std_nat_realization_agreement_test()), ct_std_nat_operators_refuse_overflow_test()), ct_render_rust_applied_type_qualified_base_test()), ct_measure_unit_variant_exact_one_test()), ct_renderer_hop_identity_keying_test()), ct_generic_param_declines_fail_closed_unwrap_test()), ct_witness_carrier_declines_non_witness_expected_type_test()), ct_kernel_identity_single_authority_test()), ct_type_reference_identity_split_test()), ct_declaration_field_reference_identity_test()), ct_same_leaf_type_declarations_emit_by_identity_test()), ct_unbound_reference_to_a_twice_declared_leaf_refuses_test()), ct_qualified_reference_is_not_decided_by_the_local_declarer_test()), ct_same_leaf_type_elsewhere_leaves_other_modules_emission_unchanged_test()), ct_unstamped_bare_optional_follows_the_lookup_binding_order_test()), ct_a_coproduct_named_optional_emits_as_its_own_enum_test()), ct_duplicate_type_parameter_refuses_test()), ct_resource_item_is_not_a_type_item_test()) } } @@ -207,7 +219,7 @@ pub fn ct_std_nat_operators_refuse_overflow_test() -> String { } pub fn ct_diagnostics_carrier_grounding_test() -> String { - v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" #[test]\n".to_string(), " fn diagnostics_carrier_grounds_to_native_option() {\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_alias(\"Diagnostics\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_alias(\"Optional\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_grounded_coproduct_native_alias(\"Diagnostics\".to_string()));\n".to_string()), " let empty_shared = std::rc::Rc::new(im::OrdSet::new());\n".to_string()), " assert_eq!(\n".to_string()), " crate::v1_compiler_emit_rust::render_rust_diagnostics_carrier_applied(empty_shared.clone()),\n".to_string()), " \"Option\"\n".to_string()), " );\n".to_string()), " let mut shared_ned_inner = im::OrdSet::new();\n".to_string()), " shared_ned_inner.insert(\"NonEmptyDiagnostics\".to_string());\n".to_string()), " let shared_ned = std::rc::Rc::new(shared_ned_inner);\n".to_string()), " assert_eq!(\n".to_string()), " crate::v1_compiler_emit_rust::render_rust_diagnostics_carrier_applied(shared_ned),\n".to_string()), " \"Option>\"\n".to_string()), " );\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_some_like_variant_name(\"Some\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_some_like_variant_name(\"Present\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_some_like_variant_name(\"None\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_some_like_variant_name(\"Absent\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_optional_like_parent_name(\"Diagnostics\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_optional_like_parent_name(\"Optional\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_optional_like_parent_name(\"Witness\".to_string()));\n".to_string()), " let diagnostics_node = named_type_node(\"Diagnostics\");\n".to_string()), " let source_indices = std::rc::Rc::new(HashMap::new());\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_type(diagnostics_node.clone(), source_indices.clone()));\n".to_string()), " let empty_emit = crate::v1_compiler_infer_emit_info::empty_emit_graph_info();\n".to_string()), " assert_eq!(\n".to_string()), " crate::v1_compiler_emit_rust::render_rust_type(\n".to_string()), " diagnostics_node,\n".to_string()), " empty_shared,\n".to_string()), " source_indices,\n".to_string()), " empty_emit\n".to_string()), " ),\n".to_string()), " \"Option\"\n".to_string()), " );\n".to_string()), " }\n\n".to_string()) + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" #[test]\n".to_string(), " fn diagnostics_carrier_grounds_to_native_option() {\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_alias(\"Diagnostics\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_alias(\"Optional\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias(\"v2.std.diagnostic\".to_string(), \"Diagnostics\".to_string()));\n".to_string()), " // The host option is a DECLARATION, not a name: the kernel optional's declaration is it, and a\n".to_string()), " // coproduct another module declares as Optional is not.\n".to_string()), " assert!(crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias(\"std.optional\".to_string(), \"Optional\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::declaration_is_grounded_coproduct_native_alias(\"gunbc.instruments.native_emission_controls_optional_collision\".to_string(), \"Optional\".to_string()));\n".to_string()), " let empty_shared = std::rc::Rc::new(im::OrdSet::new());\n".to_string()), " assert_eq!(\n".to_string()), " crate::v1_compiler_emit_rust::render_rust_diagnostics_carrier_applied(empty_shared.clone()),\n".to_string()), " \"Option\"\n".to_string()), " );\n".to_string()), " let mut shared_ned_inner = im::OrdSet::new();\n".to_string()), " shared_ned_inner.insert(\"NonEmptyDiagnostics\".to_string());\n".to_string()), " let shared_ned = std::rc::Rc::new(shared_ned_inner);\n".to_string()), " assert_eq!(\n".to_string()), " crate::v1_compiler_emit_rust::render_rust_diagnostics_carrier_applied(shared_ned),\n".to_string()), " \"Option>\"\n".to_string()), " );\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_some_like_variant_name(\"Some\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_some_like_variant_name(\"Present\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_some_like_variant_name(\"None\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_some_like_variant_name(\"Absent\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_optional_like_parent_name(\"Diagnostics\".to_string()));\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_optional_like_parent_name(\"Optional\".to_string()));\n".to_string()), " assert!(!crate::v1_compiler_emit_rust::is_optional_like_parent_name(\"Witness\".to_string()));\n".to_string()), " let diagnostics_node = named_type_node(\"Diagnostics\");\n".to_string()), " let source_indices = std::rc::Rc::new(HashMap::new());\n".to_string()), " assert!(crate::v1_compiler_emit_rust::is_host_diagnostics_carrier_type(diagnostics_node.clone(), source_indices.clone()));\n".to_string()), " let empty_emit = crate::v1_compiler_infer_emit_info::empty_emit_graph_info();\n".to_string()), " assert_eq!(\n".to_string()), " crate::v1_compiler_emit_rust::render_rust_type(\n".to_string()), " diagnostics_node,\n".to_string()), " empty_shared,\n".to_string()), " source_indices,\n".to_string()), " empty_emit\n".to_string()), " ),\n".to_string()), " \"Option\"\n".to_string()), " );\n".to_string()), " }\n\n".to_string()) } pub fn ct_rendered_leaf_occurrence_identity_test() -> String { diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 052115df96b..110abe81500 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -86,13 +86,18 @@ pub use crate::std_induction::{InductiveField, SubValueRelation}; use crate::std_literal_elaboration::KernelGroundingLookup::{ KernelGroundingAbsent, KernelGroundingAmbiguous, KernelGroundingFound, }; +use crate::std_literal_elaboration::KernelMintDeclarationLookup::{ + KernelMintDeclarationAbsent, KernelMintDeclarationAmbiguous, KernelMintDeclarationFound, +}; use crate::std_literal_elaboration::KernelMintOwnership::{ DeclarationDoesNotOwnTheMint, DeclarationOwnsTheMint, KernelMintOwnershipAmbiguous, }; use crate::std_literal_elaboration::LiteralSourceKind::KernelIntLiteral; -pub use crate::std_literal_elaboration::{kernel_grounding_for, kernel_mint_ownership}; pub use crate::std_literal_elaboration::{ - KernelGroundingLookup, KernelMintOwnership, LiteralSourceKind, + kernel_grounding_for, kernel_mint_declaration_for, kernel_mint_ownership, +}; +pub use crate::std_literal_elaboration::{ + KernelGroundingLookup, KernelMintDeclarationLookup, KernelMintOwnership, LiteralSourceKind, }; pub use crate::std_measure::millisecond_count; pub use crate::std_occurrence_identity::NodeOccurrenceIdentity; @@ -227,15 +232,28 @@ use crate::v1_compiler_infer_emit_info::TypeDeclResolution::{ TypeDeclKernelSpellingUndecided, TypeDeclLeafAmbiguous, TypeDeclNotDeclared, TypeDeclResolved, }; use crate::v1_compiler_infer_emit_info::TypeRepr::{EnumRepr, StructRepr}; +use crate::v1_compiler_infer_emit_info::TypeSummaryLookup::{ + TypeSummaryFound, TypeSummaryLeafAmbiguous, TypeSummaryNotDeclared, +}; +use crate::v1_compiler_infer_emit_info::TypeSummaryQuestion::{ + QuestionDecided, QuestionNameAmbiguous, QuestionNotDeclared, +}; pub use crate::v1_compiler_infer_emit_info::{ collect_type_node_import_surface_names, collect_type_node_import_surface_occurrences, emit_info_with_expected_type, emit_info_with_fn_return, emit_info_with_fn_type_context, empty_emit_graph_info, find_variant_parent, is_enum_in_summaries, is_known_variant, - lookup_emit_type_summary, resolve_type_decl_reference, type_decl_identity, + lookup_emit_type_summary, resolve_type_decl_reference, summary_is_enum_with_variant, + type_decl_identities_of_leaf, type_decl_identity, type_summary_answer, type_summary_decided, + type_summary_keys_of_leaf, type_summary_lookup, type_summary_of_reference, type_summary_values, variant_belongs_to_enum, variant_summary_key, }; pub use crate::v1_compiler_infer_emit_info::{ - EmitGraphInfo, TypeDeclIndex, TypeDeclResolution, TypeRepr, TypeSummary, TypeSurfaceOccurrence, + EmitGraphInfo, TypeDeclIndex, TypeDeclResolution, TypeRepr, TypeSummary, TypeSummaryIndex, + TypeSummaryLookup, TypeSummaryQuestion, TypeSurfaceOccurrence, +}; +use crate::v1_compiler_infer_env::BareOccurrenceBinding::{ + BareOccurrenceDeclaredInItsFile, BareOccurrenceImportedByName, BareOccurrenceIsKernelName, + BareOccurrenceUndecided, }; use crate::v1_compiler_infer_env::GlobalBareLookupState::{ GlobalBareAmbiguousBinding, GlobalBareUniqueBinding, @@ -244,12 +262,13 @@ use crate::v1_compiler_infer_env::UnitVariantPhantomLookup::{ UnitVariantPhantomAbsent, UnitVariantPhantomEvidenceUnavailable, UnitVariantPhantomPresent, }; pub use crate::v1_compiler_infer_env::{ - authored_name, binding_declares_span, empty_symbol_index, lookup_binding_by_name, - lookup_type_by_name, lookup_type_for, lookup_unit_variant_phantom_type, + authored_name, bare_occurrence_binding, binding_declares_span, + declaration_ref_of_declaration_node, empty_symbol_index, empty_type_env, + lookup_binding_by_name, lookup_type_by_name, lookup_type_for, lookup_unit_variant_phantom_type, type_reference_declaration_ref, }; pub use crate::v1_compiler_infer_env::{ - GlobalBareLookupState, TypeBinding, TypeEnv, UnitVariantPhantomLookup, + BareOccurrenceBinding, GlobalBareLookupState, TypeBinding, TypeEnv, UnitVariantPhantomLookup, }; use crate::v1_compiler_infer_items::ItemKind::{DataItem, OtherItem, TypeItem}; use crate::v1_compiler_infer_items::ItemLookup::{ItemFound, ItemLeafAmbiguous, ItemNotFound}; @@ -404,7 +423,11 @@ pub fn render_rust_type( if is_host_text_carrier_type(n.clone(), source_indices.clone()) { return rust_carrier_optional_wrap(n.clone(), "String".to_string()); } - if is_host_optional_carrier_type(n.clone(), source_indices.clone()) { + if is_host_optional_carrier_type( + n.clone(), + source_indices.clone(), + emit_info.fn_type_env.clone(), + ) { return render_rust_optional_carrier_applied( n.clone(), emit_info.fn_generic_param_names.clone(), @@ -588,7 +611,11 @@ pub fn render_rust_type_without_applied_binding( if is_host_text_carrier_type(n.clone(), source_indices.clone()) { return rust_carrier_optional_wrap(n.clone(), "String".to_string()); } - if is_host_optional_carrier_type(n.clone(), source_indices.clone()) { + if is_host_optional_carrier_type( + n.clone(), + source_indices.clone(), + emit_info.fn_type_env.clone(), + ) { return render_rust_optional_carrier_applied( n.clone(), emit_info.fn_generic_param_names.clone(), @@ -897,10 +924,6 @@ pub fn is_host_freemonoid_vec_alias(name: String) -> bool { (name.clone() == "FreeMonoid".to_string()) } -pub fn is_host_optional_carrier_alias(name: String) -> bool { - (name.clone() == kernel_optional_mint_name()) -} - pub fn is_host_diagnostics_carrier_alias(name: String) -> bool { { let mut __found = false; @@ -914,9 +937,95 @@ pub fn is_host_diagnostics_carrier_alias(name: String) -> bool { } } -pub fn is_grounded_coproduct_native_alias(name: String) -> bool { - ((is_host_freemonoid_vec_alias(name.clone()) || is_host_optional_carrier_alias(name.clone())) - || is_host_diagnostics_carrier_alias(name.clone())) +pub fn declaration_is_grounded_coproduct_native_alias( + mut __tco_loop_module_path: String, + mut __tco_loop_decl_name: String, +) -> bool { + loop { + #[allow(unused_mut)] + let mut module_path = __tco_loop_module_path; + #[allow(unused_mut)] + let mut decl_name = __tco_loop_decl_name; + if v1_rt::contains(decl_name.clone(), ".".to_string()) { + let segments = Rc::new( + decl_name + .clone() + .split(&".".to_string()) + .map(|s| s.to_string()) + .collect::>(), + ); + { + let __tco_0 = Rc::new( + segments + .clone() + .iter() + .cloned() + .take(v1_rt::int_sub((segments.clone().len() as i64), 1) as usize) + .collect::>(), + ) + .join(&".".to_string()); + let __tco_1 = crate::v1_std_core::qualified_last_segment(decl_name); + __tco_loop_module_path = __tco_0; + __tco_loop_decl_name = __tco_1; + continue; + } + } else { + break ((is_host_freemonoid_vec_alias(decl_name.clone()) + || declaration_owns_host_option(module_path.clone(), decl_name.clone())) + || crate::std_decl_ref::declaration_ref_in_list( + crate::std_decl_ref::decl_ref(module_path.clone(), decl_name.clone()), + rust_host_option_carrier_declarations(), + )); + } + } +} + +pub fn every_declarer_is_grounded_coproduct_native_alias( + decls: Rc, + name: String, +) -> bool { + { + let identities = crate::v1_compiler_infer_emit_info::type_decl_identities_of_leaf( + decls.clone(), + crate::v1_std_core::qualified_last_segment(name.clone()), + ); + (((identities.clone().len() as i64) > 0) && { + let mut __all = true; + for identity in identities.iter().cloned() { + if !(declaration_is_grounded_coproduct_native_alias( + "".to_string(), + identity.clone(), + )) { + __all = false; + break; + } + } + __all + }) + } +} + +pub fn summary_declares_grounded_coproduct_native_alias(summary: Rc) -> bool { + { + let segments = Rc::new( + summary + .key + .clone() + .split(&".".to_string()) + .map(|s| s.to_string()) + .collect::>(), + ); + let module_path = Rc::new( + segments + .clone() + .iter() + .cloned() + .take(v1_rt::int_sub((segments.clone().len() as i64), 1) as usize) + .collect::>(), + ) + .join(&".".to_string()); + declaration_is_grounded_coproduct_native_alias(module_path.clone(), summary.name.clone()) + } } pub fn rust_declaration_realizes_as_native_alias(module_path: String, decl_name: String) -> bool { @@ -934,13 +1043,125 @@ pub fn rust_declaration_realizes_as_native_alias(module_path: String, decl_name: } } +pub fn declaration_owns_host_option(module_path: String, decl_name: String) -> bool { + match (*crate::std_literal_elaboration::kernel_mint_ownership( + kernel_mint_declaration_rows(), + kernel_optional_mint_name(), + crate::std_decl_ref::decl_ref(module_path.clone(), decl_name.clone()), + )) + .clone() + { + KernelMintOwnership::DeclarationOwnsTheMint => true, + KernelMintOwnership::DeclarationDoesNotOwnTheMint => false, + KernelMintOwnership::KernelMintOwnershipAmbiguous { row_count: _, .. } => false, + } +} + +pub fn unstamped_reference_is_host_option( + n: Rc, + source_indices: Rc>>, + env: Rc, +) -> bool { + { + let leaf = crate::v1_std_core::authored_name_at(source_indices.clone(), n.clone()); + match (*crate::v1_compiler_infer_env::bare_occurrence_binding( + env.symbol_index.clone(), + leaf.clone(), + n.clone(), + )) + .clone() + { + BareOccurrenceBinding::BareOccurrenceDeclaredInItsFile { + declaration: decl, .. + } => { + declaration_node_owns_host_option(decl.clone(), source_indices.clone(), env.clone()) + } + BareOccurrenceBinding::BareOccurrenceImportedByName { + module_path: from_module, + declaration: decl, + .. + } => { + (declaration_owns_host_option(from_module.clone(), leaf.clone()) + || declaration_node_owns_host_option( + decl.clone(), + source_indices.clone(), + env.clone(), + )) + } + BareOccurrenceBinding::BareOccurrenceIsKernelName => { + match (*crate::std_literal_elaboration::kernel_mint_declaration_for( + kernel_mint_declaration_rows(), + leaf.clone(), + )) + .clone() + { + KernelMintDeclarationLookup::KernelMintDeclarationFound { + declaration: d, + .. + } => declaration_owns_host_option(d.module_path.clone(), d.decl_name.clone()), + KernelMintDeclarationLookup::KernelMintDeclarationAbsent => false, + KernelMintDeclarationLookup::KernelMintDeclarationAmbiguous { + row_count: _, + .. + } => false, + } + } + BareOccurrenceBinding::BareOccurrenceUndecided => false, + } + } +} + +pub fn declaration_node_owns_host_option( + decl: Rc, + source_indices: Rc>>, + env: Rc, +) -> bool { + match crate::v1_compiler_infer_env::declaration_ref_of_declaration_node( + decl.clone(), + source_indices.clone(), + env.clone(), + ) { + Some(d) => declaration_owns_host_option(d.module_path.clone(), d.decl_name.clone()), + std::option::Option::None => false, + } +} + pub fn is_host_optional_carrier_type( n: Rc, source_indices: Rc>>, + env: Rc, ) -> bool { - ((crate::v1_std_core::authored_name_at(source_indices.clone(), n.clone()) - == "Optional".to_string()) - && ((n.children.clone().len() as i64) > 0)) + match n.declaration.clone() { + Some(d) => match (*d.field.clone()).clone() { + DeclField::WholeDeclaration => { + declaration_owns_host_option(d.module_path.clone(), d.decl_name.clone()) + } + _ => false, + }, + std::option::Option::None => { + let is_declaration_structure = (((n.module_item_kind.clone() + == ParsedModuleItemKind::ModuleItemTypeDeclaration) + || (n.connective.clone() == Connective::Disj)) + && (n.ident_span.clone() != std::option::Option::None)); + let declared = if is_declaration_structure.clone() { + crate::v1_compiler_infer_env::declaration_ref_of_declaration_node( + n.clone(), + source_indices.clone(), + env.clone(), + ) + } else { + std::option::Option::None + }; + match declared.clone() { + Some(d) => declaration_owns_host_option(d.module_path.clone(), d.decl_name.clone()), + std::option::Option::None => unstamped_reference_is_host_option( + n.clone(), + source_indices.clone(), + env.clone(), + ), + } + } + } } pub fn is_host_diagnostics_carrier_type( @@ -2350,7 +2571,7 @@ pub fn render_rust_applied_type( if is_host_text_carrier_type(n.clone(), source_indices.clone()) { return rust_carrier_optional_wrap(n.clone(), "String".to_string()); } - if is_host_optional_carrier_type(n.clone(), source_indices.clone()) { + if is_host_optional_carrier_type(n.clone(), source_indices.clone(), env.clone()) { return render_rust_optional_carrier_applied( n.clone(), generic_param_names.clone(), @@ -2617,7 +2838,7 @@ pub fn render_rust_decl_type( if is_host_text_carrier_type(n.clone(), source_indices.clone()) { return rust_carrier_optional_wrap(n.clone(), "String".to_string()); } - if is_host_optional_carrier_type(n.clone(), source_indices.clone()) { + if is_host_optional_carrier_type(n.clone(), source_indices.clone(), env.clone()) { return render_rust_optional_carrier_applied( n.clone(), generic_param_names.clone(), @@ -2980,7 +3201,7 @@ pub fn render_rust_fn_sig_type( if is_host_text_carrier_type(n.clone(), source_indices.clone()) { return rust_carrier_optional_wrap(n.clone(), "String".to_string()); } - if is_host_optional_carrier_type(n.clone(), source_indices.clone()) { + if is_host_optional_carrier_type(n.clone(), source_indices.clone(), env.clone()) { return render_rust_optional_carrier_applied( n.clone(), generic_param_names.clone(), @@ -6077,7 +6298,10 @@ pub fn rust_qualify_type_leaf_name( match v1_rt::map_get(&variant_to_enum, name.clone()) { Some(parent) => { if (parent.clone() != "".to_string()) { - rust_variant_path(parent.clone(), name.clone()) + rust_variant_path( + crate::v1_std_core::qualified_last_segment(parent.clone()), + name.clone(), + ) } else { name.clone() } @@ -6368,7 +6592,7 @@ pub fn maybe_mark_shared_type( .. } => (unit_only.clone() == false), }); - if is_grounded_coproduct_native_alias(summary.name.clone()) { + if summary_declares_grounded_coproduct_native_alias(summary.clone()) { acc.clone() } else { if (needs_sharing.clone() @@ -6382,27 +6606,75 @@ pub fn maybe_mark_shared_type( } } +pub fn shared_by_every_declarer( + type_summaries: Rc, + name: String, + recursive_type_set: Rc>, + target_needs_sharing: bool, +) -> bool { + { + let mut __all = true; + for key in crate::v1_compiler_infer_emit_info::type_summary_keys_of_leaf( + type_summaries.clone(), + name.clone(), + ) + .iter() + .cloned() + { + if !(match crate::v1_compiler_infer_emit_info::type_summary_decided( + type_summaries.clone(), + key.clone(), + ) { + Some(summary) => v1_rt::set_contains( + &maybe_mark_shared_type( + v1_rt::rc_empty_set::(), + summary.clone(), + recursive_type_set.clone(), + target_needs_sharing.clone(), + ), + name.clone(), + ), + std::option::Option::None => true, + }) { + __all = false; + break; + } + } + __all + } +} + pub fn build_shared_types( - type_summaries: Rc>>, + type_summaries: Rc, recursive_type_set: Rc>, target: RenderTarget, ) -> Rc> { { let sharing = crate::v1_compiler_languages::sharing_for_target(target.clone()); - let user_shared = Rc::new(v1_rt::map_values(&type_summaries)) - .iter() - .cloned() - .fold( - v1_rt::rc_empty_set::(), - |acc: Rc>, summary: Rc| { - maybe_mark_shared_type( - acc, - summary.clone(), - recursive_type_set.clone(), - sharing.needs_sharing.clone(), - ) - }, - ); + let user_shared = + crate::v1_compiler_infer_emit_info::type_summary_values(type_summaries.clone()) + .iter() + .cloned() + .fold( + v1_rt::rc_empty_set::(), + |acc: Rc>, summary: Rc| { + if shared_by_every_declarer( + type_summaries.clone(), + summary.name.clone(), + recursive_type_set.clone(), + sharing.needs_sharing.clone(), + ) { + maybe_mark_shared_type( + acc.clone(), + summary.clone(), + recursive_type_set.clone(), + sharing.needs_sharing.clone(), + ) + } else { + acc.clone() + } + }, + ); let collection_keys = Rc::new({ let mut __result = Vec::new(); for k in Rc::new(v1_rt::sorted_map_keys(&rust_container_templates())) @@ -7966,7 +8238,7 @@ pub fn emit_inferred_type_leaf_name( pub fn anonymous_record_lit_surface_name( n: Rc, source_indices: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> String { { let lit_field_names = Rc::new({ @@ -8016,7 +8288,10 @@ pub fn anonymous_record_lit_surface_name( let rt_name = crate::v1_std_core::authored_name_at(source_indices.clone(), rt.clone()); if ((rt.ident_span.clone() != std::option::Option::None) - && v1_rt::map_contains_key(&type_summaries, rt_name.clone())) + && (crate::v1_compiler_infer_emit_info::type_summary_decided( + type_summaries.clone(), + rt_name.clone(), + ) != std::option::Option::None)) { rt_name.clone() } else { @@ -8031,7 +8306,7 @@ pub fn anonymous_record_lit_surface_name( pub fn record_lit_variant_payload_struct_surfaces( n: Rc, source_indices: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, ) -> Rc> { { @@ -8053,8 +8328,8 @@ pub fn record_lit_variant_payload_struct_surfaces( if (enum_name.clone() == "".to_string()) { Rc::new(vec![]) } else { - match v1_rt::map_get( - &type_summaries, + match crate::v1_compiler_infer_emit_info::type_summary_decided( + type_summaries.clone(), crate::v1_compiler_infer_emit_info::variant_summary_key( enum_name.clone(), variant_name.clone(), @@ -8066,17 +8341,13 @@ pub fn record_lit_variant_payload_struct_surfaces( .iter() .cloned() { - if ((ft.clone() != "".to_string()) - && match v1_rt::map_get(&type_summaries, ft.clone()) { - Some(fts) => match (*fts.repr.clone()).clone() { - TypeRepr::StructRepr => true, - _ => false, - }, - std::option::Option::None => false, - }) - { - __result.push(ft); - } + if ((ft.clone() != "".to_string()) && match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), ft.clone()) { + Some(fts) => match (*fts.repr.clone()).clone() { + TypeRepr::StructRepr => true, + _ => false, +}, + std::option::Option::None => false, +}) { __result.push(ft); } } __result }), @@ -8115,7 +8386,7 @@ pub fn record_lit_field_type_hints( pub fn record_lit_resolved_ctor_import_names( type_name: String, n: Rc, - type_summaries: Rc>>, + type_summaries: Rc, source_indices: Rc>>, ) -> Rc> { { @@ -8184,7 +8455,7 @@ pub fn record_lit_resolved_ctor_import_names( pub fn record_lit_ref_names( n: Rc, source_indices: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, ) -> Rc> { match (*n.expr_data.clone()).clone() { @@ -8269,7 +8540,7 @@ pub fn record_lit_ref_names( pub fn collect_anonymous_record_lit_heads( n: Rc, source_indices: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Rc> { stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { let self_head = match (*n.expr_data.clone()).clone() { @@ -8281,7 +8552,10 @@ pub fn collect_anonymous_record_lit_heads( let inferred = emit_inferred_type_leaf_name(n.clone(), source_indices.clone()); if ((inferred.clone() != "".to_string()) - && v1_rt::map_contains_key(&type_summaries, inferred.clone())) + && (crate::v1_compiler_infer_emit_info::type_summary_decided( + type_summaries.clone(), + inferred.clone(), + ) != std::option::Option::None)) { Rc::new(vec![inferred.clone()]) } else { @@ -8415,19 +8689,19 @@ pub fn collect_items_field_import_surface_names( let mut __result = Vec::new(); for type_name in surface_names.iter().cloned() { __result.extend((*{ - let summary_lookup = match v1_rt::map_get(&type_summaries, type_name.clone()) { + let summary_lookup = match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), type_name.clone()) { Some(summary) => Some(summary.clone()), std::option::Option::None => match v1_rt::map_get(&variant_to_enum, type_name.clone()) { Some(enum_name) => if (enum_name.clone() == "".to_string()) { std::option::Option::None } else { - v1_rt::map_get(&type_summaries, crate::v1_compiler_infer_emit_info::variant_summary_key(enum_name.clone(), type_name.clone())) + crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), crate::v1_compiler_infer_emit_info::variant_summary_key(enum_name.clone(), type_name.clone())) }, std::option::Option::None => std::option::Option::None, }, }; match summary_lookup.clone() { - Some(summary) => Rc::new({ let mut __result = Vec::new(); for field_type in summary.field_import_surface_names.clone().iter().cloned() { if ((field_type.clone() != "".to_string()) && match v1_rt::map_get(&type_summaries, field_type.clone()) { + Some(summary) => Rc::new({ let mut __result = Vec::new(); for field_type in summary.field_import_surface_names.clone().iter().cloned() { if ((field_type.clone() != "".to_string()) && match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), field_type.clone()) { Some(ft) => match (*ft.repr.clone()).clone() { TypeRepr::StructRepr => true, _ => false, @@ -8445,7 +8719,7 @@ match summary_lookup.clone() { pub fn collect_pattern_ref_names( pattern: Rc, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Rc> { stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { match (*pattern.clone()).clone() { @@ -8496,7 +8770,7 @@ pub fn collect_pattern_ref_names( pub fn collect_value_ref_names( n: Rc, source_indices: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, ) -> Rc> { stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { @@ -8759,7 +9033,7 @@ pub fn emit_scrutinee_type_name( pub fn collect_pattern_rc_prelude_parent_enums( pattern: Rc, scrut_type: String, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Rc> { match (*pattern.clone()).clone() { MatchPattern::VariantPattern { @@ -9018,7 +9292,7 @@ pub fn collect_record_lit_field_struct_surfaces( parent: Rc, field_init: Rc, source_indices: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, ) -> Rc> { { @@ -9039,30 +9313,23 @@ pub fn collect_record_lit_field_struct_surfaces( if (summary_key.clone() == "".to_string()) { Rc::new(vec![]) } else { - match v1_rt::map_get(&type_summaries, summary_key.clone()) { - Some(summary) => match v1_rt::map_get( - &summary.field_type_map.clone(), - field_name.clone(), - ) { - Some(ft) => { - if ((ft.clone() != "".to_string()) - && match v1_rt::map_get(&type_summaries, ft.clone()) { - Some(fts) => match (*fts.repr.clone()).clone() { - TypeRepr::StructRepr => true, - _ => false, - }, - std::option::Option::None => false, - }) - { - Rc::new(vec![ft.clone()]) - } else { - Rc::new(vec![]) - } - } - std::option::Option::None => Rc::new(vec![]), - }, - std::option::Option::None => Rc::new(vec![]), - } + match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), summary_key.clone()) { + Some(summary) => match v1_rt::map_get(&summary.field_type_map.clone(), field_name.clone()) { + Some(ft) => if ((ft.clone() != "".to_string()) && match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), ft.clone()) { + Some(fts) => match (*fts.repr.clone()).clone() { + TypeRepr::StructRepr => true, + _ => false, +}, + std::option::Option::None => false, +}) { + Rc::new(vec![ft.clone()]) + } else { + Rc::new(vec![]) + }, + std::option::Option::None => Rc::new(vec![]), +}, + std::option::Option::None => Rc::new(vec![]), +} } } _ => Rc::new(vec![]), @@ -9113,7 +9380,9 @@ pub fn collect_value_emit_type_surface_names( let from_variant = match v1_rt::map_get(&variant_to_enum, nm.clone()) { Some(parent) => { if (parent.clone() != "".to_string()) { - Rc::new(vec![parent.clone()]) + Rc::new(vec![crate::v1_std_core::qualified_last_segment( + parent.clone(), + )]) } else { Rc::new(vec![]) } @@ -9377,55 +9646,29 @@ pub fn reference_derived_use_lines_note() -> String { pub fn expand_variant_payload_struct_imports( names: Rc>, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, ) -> Rc> { Rc::new({ let mut __result = Vec::new(); for n in names.iter().cloned() { - __result.extend( - (*match v1_rt::map_get(&variant_to_enum, n.clone()) { - Some(enum_name) => { - if (enum_name.clone() == "".to_string()) { - Rc::new(vec![]) - } else { - match v1_rt::map_get( - &type_summaries, - crate::v1_compiler_infer_emit_info::variant_summary_key( - enum_name.clone(), - n.clone(), - ), - ) { - Some(summary) => Rc::new({ - let mut __result = Vec::new(); - for ft in - Rc::new(v1_rt::map_values(&summary.field_type_map.clone())) - .iter() - .cloned() - { - if ((ft.clone() != "".to_string()) - && match v1_rt::map_get(&type_summaries, ft.clone()) { - Some(fts) => match (*fts.repr.clone()).clone() { - TypeRepr::StructRepr => true, - _ => false, - }, - std::option::Option::None => false, - }) - { - __result.push(ft); - } - } - __result - }), - std::option::Option::None => Rc::new(vec![]), - } - } - } - std::option::Option::None => Rc::new(vec![]), - }) - .iter() - .cloned(), - ); + __result.extend((*match v1_rt::map_get(&variant_to_enum, n.clone()) { + Some(enum_name) => if (enum_name.clone() == "".to_string()) { + Rc::new(vec![]) + } else { + match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), crate::v1_compiler_infer_emit_info::variant_summary_key(enum_name.clone(), n.clone())) { + Some(summary) => Rc::new({ let mut __result = Vec::new(); for ft in Rc::new(v1_rt::map_values(&summary.field_type_map.clone())).iter().cloned() { if ((ft.clone() != "".to_string()) && match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), ft.clone()) { + Some(fts) => match (*fts.repr.clone()).clone() { + TypeRepr::StructRepr => true, + _ => false, +}, + std::option::Option::None => false, +}) { __result.push(ft); } } __result }), + std::option::Option::None => Rc::new(vec![]), +} + }, + std::option::Option::None => Rc::new(vec![]), +}).iter().cloned()); } __result }) @@ -9477,10 +9720,13 @@ pub fn reference_is_host_realized_builtin(name: String) -> bool { pub fn reference_derived_variant_induced_parent_spelled( module_source: String, enum_name: String, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, ) -> bool { - match v1_rt::map_get(&type_summaries, enum_name.clone()) { + match crate::v1_compiler_infer_emit_info::type_summary_decided( + type_summaries.clone(), + enum_name.clone(), + ) { Some(summary) => match (*summary.repr.clone()).clone() { TypeRepr::EnumRepr { unit_only: _, .. } => { let mut __found = false; @@ -9490,7 +9736,11 @@ pub fn reference_derived_variant_induced_parent_spelled( { if match v1_rt::map_get(&variant_to_enum, vn.clone()) { Some(parent) => { - ((parent.clone() == enum_name.clone()) + (((parent.clone() != "".to_string()) + && (crate::v1_std_core::qualified_last_segment(parent.clone()) + == crate::v1_std_core::qualified_last_segment( + enum_name.clone(), + ))) && reference_derived_candidate_spelled_in_module( module_source.clone(), vn.clone(), @@ -9513,7 +9763,7 @@ pub fn reference_derived_variant_induced_parent_spelled( pub fn reference_derived_candidate_authored( module_source: String, name: String, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, ) -> bool { (reference_derived_candidate_spelled_in_module(module_source.clone(), name.clone()) @@ -9812,7 +10062,7 @@ pub fn reference_derived_candidate_disposition( typed_modules: Rc>>, source_indices: Rc>>, module_index: Rc, - type_summaries: Rc>>, + type_summaries: Rc, variant_to_enum: Rc>, in_type_position: bool, ) -> Rc { @@ -9826,7 +10076,7 @@ pub fn reference_derived_candidate_disposition( } else { Rc::new( ReferenceDerivedCandidateDisposition::CandidateVariantDelegatedToParent { - parent_enum: parent.clone(), + parent_enum: crate::v1_std_core::qualified_last_segment(parent.clone()), }, ) } @@ -11217,7 +11467,8 @@ pub fn emit_module_full( for item in typed_module.items.clone().iter().cloned() { if ((((crate::v1_compiler_emit_core_support::is_type_def_item(item.clone()) && crate::v1_compiler_infer_types::is_coproduct_type(item.clone())) - && !is_grounded_coproduct_native_alias( + && !declaration_is_grounded_coproduct_native_alias( + scope.type_env.clone().module_path.clone(), crate::v1_compiler_infer_env::authored_name( scope.type_env.clone(), item.clone(), @@ -11419,7 +11670,7 @@ pub fn is_import_graph_type_name( typed_modules: Rc>>, registry: Rc>>, export_sets: Rc>>>, - type_summaries: Rc>>, + type_summaries: Rc, source_indices: Rc>>, module_index: Rc, ) -> bool { @@ -11453,10 +11704,16 @@ pub fn is_import_graph_type_name( } { true } else { - if crate::v1_compiler_infer_emit_info::is_enum_in_summaries( + if match (*crate::v1_compiler_infer_emit_info::is_enum_in_summaries( type_summaries.clone(), name.clone(), - ) { + )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + TypeSummaryQuestion::QuestionNameAmbiguous { leaf: _, .. } => false, + TypeSummaryQuestion::QuestionNotDeclared => false, + } { false } else { if crate::v1_compiler_infer_emit_info::is_known_variant( @@ -12098,7 +12355,7 @@ continue; pub fn import_module_enum_scope( import_module: String, registry: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, export_sets: Rc>>>, typed_modules: Rc>>, source_indices: Rc>>, @@ -12112,56 +12369,20 @@ pub fn import_module_enum_scope( module_index.clone(), ); let reexport_parents = match v1_rt::map_get(&export_sets, import_module.clone()) { - Some(exported) => Rc::new({ - let mut __result = Vec::new(); - for p in Rc::new({ + Some(exported) => { + Rc::new({ let mut __result = Vec::new(); - for n in Rc::new({ - let mut __result = Vec::new(); - for n in Rc::new(v1_rt::sorted_map_keys(&exported)).iter().cloned() { - if (crate::v1_compiler_infer_emit_info::is_known_variant( - type_summaries.clone(), - n.clone(), - ) && (crate::v1_compiler_infer_emit_info::is_enum_in_summaries( - type_summaries.clone(), - n.clone(), - ) == false)) - { - __result.push(n); - } - } - __result - }) - .iter() - .cloned() - { - __result.push( - match reexport_variant_parent_in_import_module( - n.clone(), - import_module.clone(), - registry.clone(), - type_summaries.clone(), - typed_modules.clone(), - export_sets.clone(), - source_indices.clone(), - module_index.clone(), - ) { - Some(parent) => parent.clone(), - std::option::Option::None => "".to_string(), - }, - ); - } + for p in Rc::new({ let mut __result = Vec::new(); for n in Rc::new({ let mut __result = Vec::new(); for n in Rc::new(v1_rt::sorted_map_keys(&exported)).iter().cloned() { if (crate::v1_compiler_infer_emit_info::is_known_variant(type_summaries.clone(), n.clone()) && match (*crate::v1_compiler_infer_emit_info::is_enum_in_summaries(type_summaries.clone(), n.clone())).clone() { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => (v.clone() == false), + TypeSummaryQuestion::QuestionNotDeclared => true, + TypeSummaryQuestion::QuestionNameAmbiguous { leaf: _, .. } => false, +}) { __result.push(n); } } __result }).iter().cloned() { __result.push(match reexport_variant_parent_in_import_module(n.clone(), import_module.clone(), registry.clone(), type_summaries.clone(), typed_modules.clone(), export_sets.clone(), source_indices.clone(), module_index.clone()) { + Some(parent) => parent.clone(), + std::option::Option::None => "".to_string(), +}); } __result }).iter().cloned() { if (p.clone() != "".to_string()) { __result.push(p); } } __result }) - .iter() - .cloned() - { - if (p.clone() != "".to_string()) { - __result.push(p); - } - } - __result - }), + } std::option::Option::None => Rc::new(vec![]), }; crate::v1_compiler_emit_core_support::unique_strings(v1_rt::concat( @@ -12645,7 +12866,7 @@ pub fn reexport_variant_parent_in_import_module( mut __tco_loop_variant_name: String, mut __tco_loop_import_module: String, mut __tco_loop_registry: Rc>>, - mut __tco_loop_type_summaries: Rc>>, + mut __tco_loop_type_summaries: Rc, mut __tco_loop_typed_modules: Rc>>, mut __tco_loop_export_sets: Rc>>>, mut __tco_loop_source_indices: Rc>>, @@ -13534,7 +13755,7 @@ pub fn import_variant_parent_for_name( n: String, import_module: String, registry: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, typed_modules: Rc>>, export_sets: Rc>>>, source_indices: Rc>>, @@ -14527,7 +14748,7 @@ Rc::new(vec![Rc::new(RustUseLine { let variant_lines = Rc::new({ let mut __result = Vec::new(); for parent in parent_list.iter().cloned() { - __result.extend((*if (is_grounded_coproduct_native_alias(parent.clone()) || rust_declaration_realizes_as_native_alias(import_module.clone(), parent.clone())) { + __result.extend((*if ((declaration_is_grounded_coproduct_native_alias(import_module.clone(), parent.clone()) || every_declarer_is_grounded_coproduct_native_alias(emit_info.type_decl_items.clone(), parent.clone())) || rust_declaration_realizes_as_native_alias(import_module.clone(), parent.clone())) { Rc::new(vec![]) } else { { @@ -14600,7 +14821,10 @@ Rc::new(vec![Rc::new(RustUseLine { } __found } == false) - && !is_grounded_coproduct_native_alias(en.clone())) + && !declaration_is_grounded_coproduct_native_alias( + import_module.clone(), + en.clone(), + )) && !rust_declaration_realizes_as_native_alias( import_module.clone(), en.clone(), @@ -15395,7 +15619,7 @@ pub fn data_field_struct_import_provider_note() -> String { pub fn module_data_field_struct_import_names( items: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, import_module: String, export_sets: Rc>>>, typed_modules: Rc>>, @@ -15416,54 +15640,26 @@ pub fn module_data_field_struct_import_names( .iter() .cloned() { - __result.extend( - (*{ - let type_name = match item.type_annotation.clone() { - Some(ta) => { - crate::v1_std_core::authored_name_at(source_indices.clone(), ta.clone()) - } - std::option::Option::None => "".to_string(), - }; - if (type_name.clone() == "".to_string()) { - Rc::new(vec![]) - } else { - match v1_rt::map_get(&type_summaries, type_name.clone()) { - Some(summary) => Rc::new({ - let mut __result = Vec::new(); - for field_type in - summary.field_import_surface_names.clone().iter().cloned() - { - if (((field_type.clone() != "".to_string()) - && name_in_transitive_export_surface( - field_type.clone(), - import_module.clone(), - Rc::new(vec![]), - export_sets.clone(), - typed_modules.clone(), - source_indices.clone(), - module_index.clone(), - )) - && match v1_rt::map_get(&type_summaries, field_type.clone()) - { - Some(ft) => match (*ft.repr.clone()).clone() { - TypeRepr::StructRepr => true, - _ => false, - }, - std::option::Option::None => false, - }) - { - __result.push(field_type); - } - } - __result - }), - std::option::Option::None => Rc::new(vec![]), - } - } - }) - .iter() - .cloned(), - ); + __result.extend((*{ + let type_name = match item.type_annotation.clone() { + Some(ta) => crate::v1_std_core::authored_name_at(source_indices.clone(), ta.clone()), + std::option::Option::None => "".to_string(), +}; +if (type_name.clone() == "".to_string()) { + Rc::new(vec![]) + } else { + match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), type_name.clone()) { + Some(summary) => Rc::new({ let mut __result = Vec::new(); for field_type in summary.field_import_surface_names.clone().iter().cloned() { if (((field_type.clone() != "".to_string()) && name_in_transitive_export_surface(field_type.clone(), import_module.clone(), Rc::new(vec![]), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone())) && match crate::v1_compiler_infer_emit_info::type_summary_decided(type_summaries.clone(), field_type.clone()) { + Some(ft) => match (*ft.repr.clone()).clone() { + TypeRepr::StructRepr => true, + _ => false, +}, + std::option::Option::None => false, +}) { __result.push(field_type); } } __result }), + std::option::Option::None => Rc::new(vec![]), +} + } +}).iter().cloned()); } __result })) @@ -16429,7 +16625,7 @@ pub fn emit_type_def_from_connective( } } } else { - if is_host_optional_carrier_alias(item_text.clone()) { + if declaration_owns_host_option(env.module_path.clone(), item_text.clone()) { { let type_params = emit_type_params(item.params.clone(), env.source_indices.clone()); @@ -16731,7 +16927,10 @@ pub fn rust_phantom_field_name() -> String { } pub fn type_has_fn_fields(name: String, emit_info: Rc) -> bool { - match v1_rt::map_get(&emit_info.type_summaries.clone(), name.clone()) { + match crate::v1_compiler_infer_emit_info::type_summary_decided( + emit_info.type_summaries.clone(), + name.clone(), + ) { Some(ts) => ts.has_fn_fields.clone(), std::option::Option::None => false, } @@ -21548,52 +21747,67 @@ pub fn emit_pattern( } } +pub fn rust_ambiguous_type_name_refusal(leaf: String) -> String { + v1_rt::concat( + v1_rt::concat( + "compile_error!(\"ambiguous type name '".to_string(), + leaf.clone(), + ), + "': declarations disagree\")".to_string(), + ) +} + pub fn pattern_parent_enum( name: String, parent_enum: Option, scrut_type: String, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Option { - { - let scrut_is_known_enum = ((scrut_type.clone() != "".to_string()) - && is_enum_type_name(scrut_type.clone(), type_summaries.clone())); - if (parent_enum.clone() != std::option::Option::None) { - parent_enum.clone() + if (parent_enum.clone() != std::option::Option::None) { + parent_enum.clone() + } else { + if (scrut_type.clone() == "".to_string()) { + unique_variant_parent(type_summaries.clone(), name.clone()) } else { - if scrut_is_known_enum.clone() { - Some(scrut_type.clone()) - } else { - unique_variant_parent(type_summaries.clone(), name.clone()) + match (*is_enum_type_name(scrut_type.clone(), type_summaries.clone())).clone() { + TypeSummaryQuestion::QuestionDecided { value: true, .. } => { + Some(scrut_type.clone()) + } + TypeSummaryQuestion::QuestionNameAmbiguous { leaf: leaf, .. } => { + Some(rust_ambiguous_type_name_refusal(leaf.clone())) + } + _ => unique_variant_parent(type_summaries.clone(), name.clone()), } } } } pub fn unique_variant_parent( - type_summaries: Rc>>, + type_summaries: Rc, variant_name: String, ) -> Option { { let parent_matches = Rc::new({ let mut __result = Vec::new(); - for type_name in Rc::new(v1_rt::sorted_map_keys(&type_summaries)) - .iter() - .cloned() + for summary in + crate::v1_compiler_infer_emit_info::type_summary_values(type_summaries.clone()) + .iter() + .cloned() { - if (is_enum_type_name(type_name.clone(), type_summaries.clone()) - && crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( - type_summaries.clone(), - variant_name.clone(), - type_name.clone(), - )) - { - __result.push(type_name); + if crate::v1_compiler_infer_emit_info::summary_is_enum_with_variant( + summary.clone(), + variant_name.clone(), + ) { + __result.push(summary); } } __result }); if ((parent_matches.clone().len() as i64) == 1) { - parent_matches.clone().first().cloned() + match parent_matches.clone().first().cloned() { + Some(summary) => Some(summary.name.clone()), + std::option::Option::None => std::option::Option::None, + } } else { std::option::Option::None } @@ -21615,8 +21829,34 @@ pub fn is_optional_variant_name(name: String) -> bool { } pub fn is_optional_like_parent_name(name: String) -> bool { - ((name.clone() == kernel_optional_mint_name()) - || is_host_diagnostics_carrier_alias(name.clone())) + if v1_rt::contains(name.clone(), ".".to_string()) { + { + let segments = Rc::new( + name.clone() + .split(&".".to_string()) + .map(|s| s.to_string()) + .collect::>(), + ); + let module_path = Rc::new( + segments + .clone() + .iter() + .cloned() + .take(v1_rt::int_sub((segments.clone().len() as i64), 1) as usize) + .collect::>(), + ) + .join(&".".to_string()); + let decl_name = crate::v1_std_core::qualified_last_segment(name.clone()); + (declaration_owns_host_option(module_path.clone(), decl_name.clone()) + || crate::std_decl_ref::declaration_ref_in_list( + crate::std_decl_ref::decl_ref(module_path.clone(), decl_name.clone()), + rust_host_option_carrier_declarations(), + )) + } + } else { + ((name.clone() == kernel_optional_mint_name()) + || is_host_diagnostics_carrier_alias(name.clone())) + } } pub fn is_some_like_variant_name(name: String) -> bool { @@ -22285,13 +22525,15 @@ pub fn analyze_rc_pattern( Some(enum_name) => { v1_rt::set_contains(&shared_types, enum_name.clone()) } - std::option::Option::None => match v1_rt::map_get( - &emit_info.type_summaries.clone(), - bare_n.clone(), - ) { - Some(_) => v1_rt::set_contains(&shared_types, bare_n.clone()), - std::option::Option::None => false, - }, + std::option::Option::None => { + match crate::v1_compiler_infer_emit_info::type_summary_decided( + emit_info.type_summaries.clone(), + bare_n.clone(), + ) { + Some(_) => v1_rt::set_contains(&shared_types, bare_n.clone()), + std::option::Option::None => false, + } + } }; let ref_bound_fields = Rc::new({ let mut __result = Vec::new(); @@ -23310,7 +23552,10 @@ pub fn rust_as_ref_let_is_irrefutable( ); match resolved.clone() { Some(enum_name) => { - match v1_rt::map_get(&emit_info.type_summaries.clone(), enum_name.clone()) { + match crate::v1_compiler_infer_emit_info::type_summary_decided( + emit_info.type_summaries.clone(), + enum_name.clone(), + ) { Some(summary) => { ((Rc::new(v1_rt::sorted_map_keys(&summary.variant_name_set.clone())) .len() as i64) @@ -23708,7 +23953,9 @@ pub fn freemonoid_empty_from_variant_parent(leaf_name: String, enum_name: String pub fn freemonoid_empty_from_emit_info(leaf_name: String, emit_info: Rc) -> bool { ((leaf_name.clone() == "Empty".to_string()) && match v1_rt::map_get(&emit_info.variant_to_enum.clone(), "Empty".to_string()) { - Some(p) => (p.clone() == "FreeMonoid".to_string()), + Some(p) => { + (crate::v1_std_core::qualified_last_segment(p.clone()) == "FreeMonoid".to_string()) + } std::option::Option::None => false, }) } @@ -23732,11 +23979,16 @@ pub fn effective_variant_parent_from_enum_lookup( let rt_name = crate::v1_std_core::authored_name_at(source_indices.clone(), rt.clone()); if (((rt.ident_span.clone() != std::option::Option::None) && (rt_name.clone() != leaf_name.clone())) - && crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( + && match (*crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( emit_info.type_summaries.clone(), leaf_name.clone(), rt_name.clone(), )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + _ => false, + }) { Some(rt_name.clone()) } else { @@ -23788,7 +24040,7 @@ pub fn effective_variant_parent( let cached = match v1_rt::map_get(&emit_info.variant_to_enum.clone(), leaf_name.clone()) { Some(p) => { if (p.clone() != "".to_string()) { - Some(p.clone()) + Some(crate::v1_std_core::qualified_last_segment(p.clone())) } else { std::option::Option::None } @@ -25443,11 +25695,19 @@ pub fn emit_rust_expr_record_lit( }; let concrete_peel_would_erase_optional_ctor = (is_optional_variant_name(variant_name.clone()) - && !crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( + && match (*crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( emit_info.type_summaries.clone(), variant_name.clone(), crate::v1_std_core::authored_name_at(si.clone(), expanded_rt.clone()), - )); + )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => { + (v.clone() == false) + } + TypeSummaryQuestion::QuestionNotDeclared => true, + TypeSummaryQuestion::QuestionNameAmbiguous { leaf: _, .. } => false, + }); let peeled_type_name = if ((((parent_enum.clone() == std::option::Option::None) && (expanded_rt.connective.clone() == Connective::Conj)) && (expanded_rt.ident_span.clone() != std::option::Option::None)) @@ -26141,8 +26401,8 @@ pub fn emit_cloned_arg( pub fn is_enum_type_name( type_name: String, - type_summaries: Rc>>, -) -> bool { + type_summaries: Rc, +) -> Rc { crate::v1_compiler_infer_emit_info::is_enum_in_summaries( type_summaries.clone(), type_name.clone(), @@ -26160,11 +26420,16 @@ pub fn contextual_variant_parent_from_type_name( crate::v1_std_core::authored_name_at(source_indices.clone(), resolved_type.clone()); if (((resolved_type.ident_span.clone() != std::option::Option::None) && (rt_name.clone() != variant_name.clone())) - && crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( + && match (*crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( emit_info.type_summaries.clone(), variant_name.clone(), rt_name.clone(), )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + _ => false, + }) { Some(rt_name.clone()) } else { @@ -26210,11 +26475,16 @@ pub fn contextual_variant_parent( ) -> Option { match parent_enum.clone() { Some(explicit_parent) => { - if crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( + if match (*crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( emit_info.type_summaries.clone(), variant_name.clone(), explicit_parent.clone(), - ) { + )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + _ => false, + } { Some(explicit_parent.clone()) } else { std::option::Option::None @@ -26551,7 +26821,11 @@ pub fn rust_call_arg_fail_closed_unwrap( let param_type = crate::v1_std_core::param_node_type_expr(param.clone()); let param_required = (((param_type.return_cardinality.clone() != Cardinality::CardOptional) - && !is_host_optional_carrier_type(param_type.clone(), source_indices.clone())) + && !is_host_optional_carrier_type( + param_type.clone(), + source_indices.clone(), + crate::v1_compiler_infer_env::empty_type_env(), + )) && !rust_param_type_is_type_variable( param_type.clone(), source_indices.clone(), @@ -30438,7 +30712,7 @@ pub fn freemonoid_match_arm_for(arms: Rc>>, variant: String) -> Opt pub fn arm_resolved_parent_enum( arm: Rc, scrut_type: String, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Option { match (*crate::v1_std_core::arm_pattern(arm.clone())).clone() { MatchPattern::VariantPattern { @@ -30485,7 +30759,7 @@ pub fn freemonoid_catchall_arm(arms: Rc>>) -> Option> { pub fn arms_are_freemonoid_coproduct( arms: Rc>>, scrut_type: String, - type_summaries: Rc>>, + type_summaries: Rc, ) -> bool { { let has_empty = match freemonoid_match_arm_for(arms.clone(), "Empty".to_string()) { @@ -33088,11 +33362,16 @@ pub fn emit_field_value_with_context( }; let corrected_parent = match expected_type.clone() { Some(et) => { - if crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( + if match (*crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( emit_info.type_summaries.clone(), variant_name.clone(), et.clone(), - ) { + )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + _ => false, + } { Some(et.clone()) } else { pe.clone() @@ -33202,7 +33481,7 @@ pub fn record_field_expected_type( pub fn struct_candidates_by_field_names( field_names: Rc>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Rc>> { { let n_fields = (field_names.clone().len() as i64); @@ -33211,7 +33490,11 @@ pub fn struct_candidates_by_field_names( } Rc::new({ let mut __result = Vec::new(); - for summary in Rc::new(v1_rt::map_values(&type_summaries)).iter().cloned() { + for summary in + crate::v1_compiler_infer_emit_info::type_summary_values(type_summaries.clone()) + .iter() + .cloned() + { if match (*summary.repr.clone()).clone() { TypeRepr::StructRepr => { ({ @@ -33317,7 +33600,7 @@ pub fn effectful_self_recursion_diagnostics( pub fn anonymous_record_struct_candidates( field_names: Rc>, field_type_hints: Rc>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Rc>> { { let candidates = @@ -33368,7 +33651,7 @@ pub fn anonymous_record_struct_candidates( pub fn ambiguous_anonymous_record_literal_diagnostics( n: Rc, - type_summaries: Rc>>, + type_summaries: Rc, source_indices: Rc>>, module_name: String, ) -> Rc>> { @@ -33551,7 +33834,7 @@ pub fn ambiguous_anonymous_record_literal_diagnostics( pub fn find_struct_name_by_fields( field_names: Rc>, field_type_hints: Rc>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Option { { let candidates = anonymous_record_struct_candidates( @@ -33572,7 +33855,7 @@ pub fn find_struct_name_by_fields( pub fn find_unique_struct_name_by_fields( field_names: Rc>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Option { { let candidates = @@ -33614,7 +33897,10 @@ pub fn emit_typed_record_lit( resolved_type.clone(), ); if ((resolved_type.ident_span.clone() != std::option::Option::None) - && v1_rt::map_contains_key(&emit_info.type_summaries.clone(), rt_name.clone())) + && (crate::v1_compiler_infer_emit_info::type_summary_decided( + emit_info.type_summaries.clone(), + rt_name.clone(), + ) != std::option::Option::None)) { Some(rt_name.clone()) } else { @@ -33895,8 +34181,10 @@ pub fn emit_typed_record_lit( ) { return "panic!(\"record-shaped carrier has no realization in the selected Rust target inhabitant\")".to_string(); } - let tn_is_known_struct = - v1_rt::map_contains_key(&emit_info.type_summaries.clone(), tn.clone()); + let tn_is_known_struct = (crate::v1_compiler_infer_emit_info::type_summary_decided( + emit_info.type_summaries.clone(), + tn.clone(), + ) != std::option::Option::None); let ctor_name = if tn_is_known_struct.clone() { tn.clone() } else { @@ -33963,11 +34251,16 @@ pub fn emit_typed_record_lit( && (rt_name.clone() != variant_surface_name.clone())) && !rt_is_type_var.clone()) && (rt_name.clone() != "Error".to_string())) - && crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( + && match (*crate::v1_compiler_infer_emit_info::variant_belongs_to_enum( emit_info.type_summaries.clone(), variant_surface_name.clone(), rt_name.clone(), )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + _ => false, + }) { Some(rt_name.clone()) } else { diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 1b84f5114e5..8e84ca034b8 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -121,13 +121,21 @@ pub use crate::v1_compiler_infer_cycle::detect_type_cycles_kahn; pub use crate::v1_compiler_infer_emit_info::DataVariantWireSpelling; use crate::v1_compiler_infer_emit_info::DataVariantWireSpelling::*; use crate::v1_compiler_infer_emit_info::TypeRepr::{EnumRepr, StructRepr}; +use crate::v1_compiler_infer_emit_info::TypeSummaryLookup::{ + TypeSummaryFound, TypeSummaryLeafAmbiguous, TypeSummaryNotDeclared, +}; +use crate::v1_compiler_infer_emit_info::TypeSummaryQuestion::{ + QuestionDecided, QuestionNameAmbiguous, QuestionNotDeclared, +}; pub use crate::v1_compiler_infer_emit_info::{ add_emit_item_summary, build_enum_field_summaries, build_struct_field_summaries, close_fn_fields, derive_variant_to_enum, empty_emit_graph_info, empty_type_decl_index, - empty_type_env, lookup_emit_type_summary, type_decl_index_with_qualified_names, + empty_type_env, empty_type_summary_index, is_enum_in_summaries, lookup_emit_type_summary, + type_decl_index_with_qualified_names, type_summary_lookup, }; pub use crate::v1_compiler_infer_emit_info::{ - EmitGraphInfo, EmitInfoBuildState, TypeRepr, TypeSummary, + EmitGraphInfo, EmitInfoBuildState, TypeRepr, TypeSummary, TypeSummaryIndex, TypeSummaryLookup, + TypeSummaryQuestion, }; use crate::v1_compiler_infer_env::GlobalBareLookupState::{ GlobalBareAmbiguousBinding, GlobalBareUniqueBinding, @@ -143,11 +151,11 @@ pub use crate::v1_compiler_infer_env::{ is_recursive_type_by_name, listed_import_required_bare_call_blocked, lookup_binding_by_name, lookup_binding_on_chain, lookup_type, lookup_type_by_name, lookup_type_for, merge_inductive_fields, merge_type_env_cache, merge_type_env_cache_guarded, node_with_children, - 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, text_crossing_by_identity, - text_representation_by_identity, text_representation_is_text_arm, + node_with_inferred, overlay_skips_kernel_name, 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, + text_crossing_by_identity, text_representation_by_identity, text_representation_is_text_arm, text_representation_is_unidentified, text_representations_cross, type_reference_declaration, type_reference_declaration_ref, unit_variant_index_shadow_insert, }; @@ -25478,32 +25486,84 @@ pub fn symbol_index_insert_unique_disj_variant_aliases( ) -> Rc { { let counts = disj_variant_name_counts(items.clone(), source_indices.clone()); - items.iter().cloned().fold(index.clone(), |acc: Rc, item: Rc| match item.connective.clone() { - Connective::Disj => { - let tname = crate::v1_std_core::authored_name_at(source_indices.clone(), item.clone()); -item.children.clone().iter().cloned().fold(acc.clone(), |a2: Rc, child: Rc| { - let vname = crate::v1_std_core::authored_name_at(source_indices.clone(), child.clone()); -let a2_qualified = crate::v1_compiler_infer_env::symbol_index_insert(a2, v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(module_path.clone(), ".".to_string()), tname.clone()), ".".to_string()), vname.clone()), item.clone()); -match v1_rt::map_get(&counts, vname.clone()) { - Some(1) => match v1_rt::map_get(&corpus_variant_counts, vname.clone()) { - Some(1) => if ((v1_rt::map_get(&corpus_item_counts, vname.clone()) != std::option::Option::None) || overlay_skips_kernel_name(vname.clone())) { - crate::v1_compiler_infer_env::symbol_index_insert(a2_qualified.clone(), v1_rt::concat(v1_rt::concat(module_path.clone(), ".".to_string()), vname.clone()), item.clone()) - } else { - crate::v1_compiler_infer_env::symbol_index_insert_decl(a2_qualified.clone(), module_path.clone(), Rc::new(TypeBinding { - name: vname.clone(), - resolved: item.clone(), - provenance: Rc::new(SubValueRelation::SubValueUnknown), - alias_rhs: std::option::Option::None, -})) - }, - _ => crate::v1_compiler_infer_env::symbol_index_insert(a2_qualified.clone(), v1_rt::concat(v1_rt::concat(module_path.clone(), ".".to_string()), vname.clone()), item.clone()), -}, - _ => a2_qualified.clone(), -} -}) -}, - _ => acc.clone(), -}) + items.iter().cloned().fold( + index.clone(), + |acc: Rc, item: Rc| match item.connective.clone() { + Connective::Disj => { + let tname = + crate::v1_std_core::authored_name_at(source_indices.clone(), item.clone()); + item.children.clone().iter().cloned().fold( + acc.clone(), + |a2: Rc, child: Rc| { + let vname = crate::v1_std_core::authored_name_at( + source_indices.clone(), + child.clone(), + ); + let a2_qualified = crate::v1_compiler_infer_env::symbol_index_insert( + a2, + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat(module_path.clone(), ".".to_string()), + tname.clone(), + ), + ".".to_string(), + ), + vname.clone(), + ), + item.clone(), + ); + match v1_rt::map_get(&counts, vname.clone()) { + Some(1) => match v1_rt::map_get( + &corpus_variant_counts, + vname.clone(), + ) { + Some(1) => if ((v1_rt::map_get( + &corpus_item_counts, + vname.clone(), + ) != std::option::Option::None) + || crate::v1_compiler_infer_env::overlay_skips_kernel_name( + vname.clone(), + )) { + crate::v1_compiler_infer_env::symbol_index_insert( + a2_qualified.clone(), + v1_rt::concat( + v1_rt::concat(module_path.clone(), ".".to_string()), + vname.clone(), + ), + item.clone(), + ) + } else { + crate::v1_compiler_infer_env::symbol_index_insert_decl( + a2_qualified.clone(), + module_path.clone(), + Rc::new(TypeBinding { + name: vname.clone(), + resolved: item.clone(), + provenance: Rc::new( + SubValueRelation::SubValueUnknown, + ), + alias_rhs: std::option::Option::None, + }), + ) + }, + _ => crate::v1_compiler_infer_env::symbol_index_insert( + a2_qualified.clone(), + v1_rt::concat( + v1_rt::concat(module_path.clone(), ".".to_string()), + vname.clone(), + ), + item.clone(), + ), + }, + _ => a2_qualified.clone(), + } + }, + ) + } + _ => acc.clone(), + }, + ) } } @@ -25965,6 +26025,38 @@ pub fn transparent_alias_identity_agrees( } } +pub fn file_named_imports_of( + module_node: Rc, + source_indices: Rc>>, +) -> Rc> { + Rc::new({ + let mut __result = Vec::new(); + for imp in crate::v1_std_core::module_imports(module_node.clone()) + .iter() + .cloned() + { + if !crate::v1_std_core::import_is_all(imp.clone()) { + __result.push(imp); + } + } + __result + }) + .iter() + .cloned() + .fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, imp: Rc| { + let from_module = import_module_path_at(imp.clone(), source_indices.clone()); + crate::v1_std_core::import_specific_names_at(imp.clone(), source_indices.clone()) + .iter() + .cloned() + .fold(acc, |inner: Rc>, name: String| { + v1_rt::rc_map_insert(inner, name.clone(), from_module.clone()) + }) + }, + ) +} + pub fn build_symbol_index_census_raw_nodes( module_nodes: Rc>>, source_indices: Rc>>, @@ -26017,6 +26109,32 @@ pub fn build_symbol_index_census_raw_nodes( module_nodes.clone(), source_indices.clone(), ), + file_modules: module_nodes.iter().cloned().fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, module_node: Rc| { + v1_rt::rc_map_insert( + acc, + module_node.span.clone().file.clone(), + crate::v1_std_core::authored_name_at( + source_indices.clone(), + module_node.clone(), + ), + ) + }, + ), + module_named_imports: module_nodes.iter().cloned().fold( + v1_rt::rc_empty_map::>>(), + |acc: Rc>>>, module_node: Rc| { + v1_rt::rc_map_insert( + acc, + crate::v1_std_core::authored_name_at( + source_indices.clone(), + module_node.clone(), + ), + file_named_imports_of(module_node.clone(), source_indices.clone()), + ) + }, + ), }) } } @@ -26581,6 +26699,8 @@ pub fn census_bare_fill_with_resolved_fn_sigs( services: services2.clone(), transparent_alias_rep: index.transparent_alias_rep.clone(), type_head_exposures: index.type_head_exposures.clone(), + file_modules: index.file_modules.clone(), + module_named_imports: index.module_named_imports.clone(), }) } } @@ -26625,6 +26745,8 @@ pub fn census_with_resolved_fn_sigs( services: fill.services.clone(), transparent_alias_rep: fill.transparent_alias_rep.clone(), type_head_exposures: fill.type_head_exposures.clone(), + file_modules: fill.file_modules.clone(), + module_named_imports: fill.module_named_imports.clone(), }) } } @@ -26668,6 +26790,14 @@ pub fn symbol_index_with_bare_fill( tree.type_head_exposures.clone(), closure.type_head_exposures.clone(), ), + file_modules: v1_rt::rc_map_merge( + tree.file_modules.clone(), + closure.file_modules.clone(), + ), + module_named_imports: v1_rt::rc_map_merge( + tree.module_named_imports.clone(), + closure.module_named_imports.clone(), + ), }) } } @@ -26753,6 +26883,14 @@ pub fn symbol_index_with_qualified_fill( fill.type_head_exposures.clone(), closure.type_head_exposures.clone(), ), + file_modules: v1_rt::rc_map_merge( + fill.file_modules.clone(), + closure.file_modules.clone(), + ), + module_named_imports: v1_rt::rc_map_merge( + fill.module_named_imports.clone(), + closure.module_named_imports.clone(), + ), }) } } @@ -26766,15 +26904,6 @@ pub fn direct_import_export_precedence_note() -> String { CACHED.with(|c: &String| c.clone()) } -pub fn overlay_skips_kernel_name(name: String) -> bool { - (((((crate::std_types::is_kernel_type(name.clone()) - || crate::std_types::is_container_type(name.clone())) - || (name.clone() == "Unit".to_string())) - || (name.clone() == "Optional".to_string())) - || (name.clone() == "Present".to_string())) - || (name.clone() == "Absent".to_string())) -} - pub fn overlay_direct_import_exports( ancestry_str_bindings: Rc>>, resolved_imports: Rc>>, @@ -26810,7 +26939,7 @@ pub fn overlay_direct_import_exports( selected.iter().cloned().fold( acc.clone(), |bacc: Rc>>, name: String| { - if overlay_skips_kernel_name(name.clone()) { + if crate::v1_compiler_infer_env::overlay_skips_kernel_name(name.clone()) { bacc.clone() } else { match v1_rt::map_get(&export_surface.str_bindings.clone(), name.clone()) @@ -31639,18 +31768,19 @@ pub fn enum_variant_shape_sets_for_item( acc: Rc, item: Rc, si: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Rc { { let item_name = crate::v1_std_core::authored_name_at(si.clone(), item.clone()); - let is_enum = match v1_rt::map_get(&type_summaries, item_name.clone()) { - Some(summary) => match (*summary.repr.clone()).clone() { - TypeRepr::EnumRepr { unit_only: _, .. } => true, - _ => false, - }, - std::option::Option::None => false, - }; - if is_enum.clone() { + if match (*crate::v1_compiler_infer_emit_info::is_enum_in_summaries( + type_summaries.clone(), + item_name.clone(), + )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + _ => false, + } { item.children.clone().iter().cloned().fold( acc, |vacc: Rc, variant: Rc| { @@ -31692,7 +31822,7 @@ pub fn enum_variant_shape_sets_for_item( pub fn build_enum_variant_shape_sets( modules: Rc>>, - type_summaries: Rc>>, + type_summaries: Rc, ) -> Rc { modules.iter().cloned().fold( Rc::new(EnumVariantShapeSets { @@ -31817,7 +31947,7 @@ pub fn build_emit_graph_info( std::option::Option::None => crate::v1_compiler_infer_env::empty_symbol_index(), }; let init = Rc::new(EmitInfoBuildState { - type_summaries: v1_rt::rc_empty_map::>(), + type_summaries: crate::v1_compiler_infer_emit_info::empty_type_summary_index(), type_decl_items: crate::v1_compiler_infer_emit_info::type_decl_index_with_qualified_names( crate::v1_compiler_infer_emit_info::empty_type_decl_index(), diff --git a/src/v1/stage0/src/v1_compiler_infer_emit_info.rs b/src/v1/stage0/src/v1_compiler_infer_emit_info.rs index fc2047dca7a..b84b00064b5 100644 --- a/src/v1/stage0/src/v1_compiler_infer_emit_info.rs +++ b/src/v1/stage0/src/v1_compiler_infer_emit_info.rs @@ -2,21 +2,36 @@ // Source module: v1.compiler.infer_emit_info use self::DataVariantWireSpelling::*; +use self::TypeDeclOccurrenceBinding::*; use self::TypeDeclReferenceRoute::*; use self::TypeDeclResolution::*; use self::TypeRepr::*; +use self::TypeSummaryLookup::*; +use self::TypeSummaryQuestion::*; +pub use crate::gunbc_structural_realization_bindings::kernel_mint_declaration_rows; use crate::std_decl_ref::DeclField::{NamedField, TypeParameter, WholeDeclaration}; pub use crate::std_decl_ref::{DeclField, DeclarationRef}; pub use crate::std_dissolution::DissolutionCondition; use crate::std_dissolution::DissolutionCondition::*; pub use crate::std_dissolution::{dissolution_description, unbound_dissolution}; +pub use crate::std_literal_elaboration::kernel_mint_declaration_for; +pub use crate::std_literal_elaboration::KernelMintDeclarationLookup; +use crate::std_literal_elaboration::KernelMintDeclarationLookup::{ + KernelMintDeclarationAbsent, KernelMintDeclarationAmbiguous, KernelMintDeclarationFound, +}; pub use crate::std_types::is_kernel_type; pub use crate::std_types::SourceSpan; pub use crate::v1_compiler_artifact::RenderTarget; use crate::v1_compiler_artifact::RenderTarget::Rust; pub use crate::v1_compiler_coercion::{declaration_realization, realized_checkpoint}; -pub use crate::v1_compiler_infer_env::{empty_symbol_index, empty_type_env, symbol_index_lookup}; -pub use crate::v1_compiler_infer_env::{SymbolIndex, TypeEnv}; +use crate::v1_compiler_infer_env::BareOccurrenceBinding::{ + BareOccurrenceDeclaredInItsFile, BareOccurrenceImportedByName, BareOccurrenceIsKernelName, + BareOccurrenceUndecided, +}; +pub use crate::v1_compiler_infer_env::{ + bare_occurrence_binding, empty_symbol_index, empty_type_env, symbol_index_lookup, +}; +pub use crate::v1_compiler_infer_env::{BareOccurrenceBinding, SymbolIndex, TypeEnv}; use crate::v1_compiler_infer_types::TextJudgment::{TextJudgedIn, TextNotAsked}; use crate::v1_compiler_infer_types::TextNotAskedReason::{ TextNotAskedForCallableComponentResidue, TextNotAskedInVariantFieldSummary, @@ -77,6 +92,7 @@ impl TypeRepr { #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct TypeSummary { pub name: String, + pub key: String, pub repr: Rc, pub field_summaries: Rc>>, pub field_type_map: Rc>, @@ -86,6 +102,177 @@ pub struct TypeSummary { pub has_fn_fields: bool, } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct TypeSummaryIndex { + pub by_key: Rc>>, + pub keys_by_leaf: Rc>>>, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum TypeSummaryLookup { + TypeSummaryFound { summary: Rc }, + TypeSummaryLeafAmbiguous { leaf: String }, + TypeSummaryNotDeclared, +} + +pub fn empty_type_summary_index() -> Rc { + Rc::new(TypeSummaryIndex { + by_key: v1_rt::rc_empty_map::>(), + keys_by_leaf: v1_rt::rc_empty_map::>>(), + }) +} + +pub fn type_summary_index_insert( + index: Rc, + key: String, + leaf: String, + summary: Rc, +) -> Rc { + Rc::new(TypeSummaryIndex { + by_key: v1_rt::rc_map_insert(index.by_key.clone(), key.clone(), summary.clone()), + keys_by_leaf: v1_rt::rc_map_insert( + index.keys_by_leaf.clone(), + leaf.clone(), + type_decl_leaf_identities_with( + v1_rt::map_get(&index.keys_by_leaf.clone(), leaf.clone()), + key.clone(), + ), + ), + }) +} + +pub fn type_summary_keys_of_leaf(index: Rc, leaf: String) -> Rc> { + match v1_rt::map_get(&index.keys_by_leaf.clone(), leaf.clone()) { + Some(keys) => keys.clone(), + std::option::Option::None => Rc::new(vec![]), + } +} + +pub fn type_summary_at_key(index: Rc, key: String) -> Rc { + match v1_rt::map_get(&index.by_key.clone(), key.clone()) { + Some(summary) => Rc::new(TypeSummaryLookup::TypeSummaryFound { + summary: summary.clone(), + }), + std::option::Option::None => Rc::new(TypeSummaryLookup::TypeSummaryNotDeclared), + } +} + +pub fn type_summary_by_leaf(index: Rc, leaf: String) -> Rc { + { + let keys = type_summary_keys_of_leaf(index.clone(), leaf.clone()); + if ((keys.clone().len() as i64) == 1) { + keys.iter().cloned().fold( + Rc::new(TypeSummaryLookup::TypeSummaryNotDeclared), + |_acc: Rc, key: String| { + type_summary_at_key(index.clone(), key.clone()) + }, + ) + } else { + if ((keys.clone().len() as i64) > 1) { + Rc::new(TypeSummaryLookup::TypeSummaryLeafAmbiguous { leaf: leaf.clone() }) + } else { + Rc::new(TypeSummaryLookup::TypeSummaryNotDeclared) + } + } + } +} + +pub fn type_summary_lookup(index: Rc, key: String) -> Rc { + stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { + match v1_rt::map_get(&index.by_key.clone(), key.clone()) { + Some(summary) => Rc::new(TypeSummaryLookup::TypeSummaryFound { + summary: summary.clone(), + }), + std::option::Option::None => { + if v1_rt::contains(key.clone(), "::".to_string()) { + { + let parts = Rc::new( + key.clone() + .split(&"::".to_string()) + .map(|s| s.to_string()) + .collect::>(), + ); + let enum_part = Rc::new( + parts + .clone() + .iter() + .cloned() + .take(v1_rt::int_sub((parts.clone().len() as i64), 1) as usize) + .collect::>(), + ) + .join(&"::".to_string()); + let variant_part = match parts.clone().last().cloned() { + Some(v) => v.clone(), + std::option::Option::None => "".to_string(), + }; + match (*type_summary_lookup(index.clone(), enum_part.clone())).clone() { + TypeSummaryLookup::TypeSummaryFound { summary: owner, .. } => { + type_summary_at_key( + index.clone(), + variant_summary_key(owner.key.clone(), variant_part.clone()), + ) + } + TypeSummaryLookup::TypeSummaryLeafAmbiguous { leaf: l, .. } => { + Rc::new(TypeSummaryLookup::TypeSummaryLeafAmbiguous { + leaf: l.clone(), + }) + } + TypeSummaryLookup::TypeSummaryNotDeclared => { + Rc::new(TypeSummaryLookup::TypeSummaryNotDeclared) + } + } + } + } else { + if v1_rt::contains(key.clone(), ".".to_string()) { + Rc::new(TypeSummaryLookup::TypeSummaryNotDeclared) + } else { + type_summary_by_leaf(index.clone(), key.clone()) + } + } + } + } + }) +} + +pub fn type_summary_of_reference( + index: Rc, + decls: Rc, + type_expr: Rc, + source_indices: Rc>>, +) -> Rc { + match (*resolve_type_decl_reference(decls.clone(), type_expr.clone(), source_indices.clone())) + .clone() + { + TypeDeclResolution::TypeDeclResolved { identity, .. } => { + type_summary_at_key(index.clone(), identity.clone()) + } + TypeDeclResolution::TypeDeclLeafAmbiguous { leaf: l, .. } => { + Rc::new(TypeSummaryLookup::TypeSummaryLeafAmbiguous { leaf: l.clone() }) + } + TypeDeclResolution::TypeDeclKernelSpellingUndecided { leaf: l, .. } => { + Rc::new(TypeSummaryLookup::TypeSummaryLeafAmbiguous { leaf: l.clone() }) + } + TypeDeclResolution::TypeDeclNotDeclared => { + Rc::new(TypeSummaryLookup::TypeSummaryNotDeclared) + } + } +} + +pub fn type_summary_decided(index: Rc, key: String) -> Option> { + match (*type_summary_lookup(index.clone(), key.clone())).clone() { + TypeSummaryLookup::TypeSummaryFound { + summary: summary, .. + } => Some(summary.clone()), + TypeSummaryLookup::TypeSummaryLeafAmbiguous { leaf: _, .. } => std::option::Option::None, + TypeSummaryLookup::TypeSummaryNotDeclared => std::option::Option::None, + } +} + +pub fn type_summary_values(index: Rc) -> Rc>> { + Rc::new(v1_rt::map_values(&index.by_key.clone())) +} + #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct FieldTypeMapBuild { pub field_types: Rc>, @@ -231,6 +418,31 @@ pub struct TypeDeclIndex { pub qualified_names: Rc, } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum TypeDeclOccurrenceBinding { + OccurrenceDeclaredHere { identity: String }, + OccurrenceImported { identity: String }, + OccurrenceIsKernelName, + OccurrenceUndecided, +} +impl TypeDeclOccurrenceBinding { + pub fn identity(&self) -> String { + match self { + TypeDeclOccurrenceBinding::OccurrenceDeclaredHere { + identity: __val, .. + } => __val.clone(), + TypeDeclOccurrenceBinding::OccurrenceImported { + identity: __val, .. + } => __val.clone(), + TypeDeclOccurrenceBinding::OccurrenceIsKernelName => { + panic!("no identity on unit variant") + } + TypeDeclOccurrenceBinding::OccurrenceUndecided => panic!("no identity on unit variant"), + } + } +} + #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(tag = "_variant")] pub enum TypeDeclResolution { @@ -401,6 +613,8 @@ pub enum TypeDeclReferenceRoute { RouteDeclaringSpan, RouteReferencingModuleDeclarer, RouteQualifiedSpelling, + RouteReferencingModuleImport, + RouteKernelMint, RouteLeafSpelling, } @@ -465,7 +679,7 @@ pub fn resolve_type_decl_routed( let referencing_module_identity = match (*by_spelling.clone()).clone() { TypeDeclResolution::TypeDeclLeafAmbiguous { leaf: l, .. } => { if (authored.clone() == l.clone()) { - type_decl_referencing_module_declarer( + type_decl_occurrence_identity( index.clone(), l.clone(), type_expr.clone(), @@ -482,11 +696,12 @@ pub fn resolve_type_decl_routed( }; match referencing_module_identity.clone() { Some(identity) => Rc::new(TypeDeclRoutedResolution { - route: if (authored.clone() == leaf.clone()) { - TypeDeclReferenceRoute::RouteReferencingModuleDeclarer - } else { - TypeDeclReferenceRoute::RouteQualifiedSpelling - }, + route: type_decl_spelling_route( + index.clone(), + authored.clone(), + leaf.clone(), + type_expr.clone(), + ), resolution: type_decl_resolution_at_identity( index.clone(), identity.clone(), @@ -519,6 +734,136 @@ pub fn type_decl_qualifier_declarer(index: Rc, authored: String) } } +pub fn type_decl_kernel_mint_declarer(index: Rc, leaf: String) -> Option { + match (*crate::std_literal_elaboration::kernel_mint_declaration_for( + kernel_mint_declaration_rows(), + leaf.clone(), + )) + .clone() + { + KernelMintDeclarationLookup::KernelMintDeclarationFound { declaration: d, .. } => { + let identity = type_decl_identity(d.module_path.clone(), d.decl_name.clone()); + match v1_rt::map_get(&index.by_identity.clone(), identity.clone()) { + Some(_) => Some(identity.clone()), + std::option::Option::None => std::option::Option::None, + } + } + KernelMintDeclarationLookup::KernelMintDeclarationAbsent => std::option::Option::None, + KernelMintDeclarationLookup::KernelMintDeclarationAmbiguous { row_count: _, .. } => { + std::option::Option::None + } + } +} + +pub fn type_decl_spelling_route( + index: Rc, + authored: String, + leaf: String, + reference: Rc, +) -> TypeDeclReferenceRoute { + if (authored.clone() != leaf.clone()) { + TypeDeclReferenceRoute::RouteQualifiedSpelling + } else { + match (*type_decl_occurrence_binding(index.clone(), leaf.clone(), reference.clone())) + .clone() + { + TypeDeclOccurrenceBinding::OccurrenceDeclaredHere { identity: _, .. } => { + TypeDeclReferenceRoute::RouteReferencingModuleDeclarer + } + TypeDeclOccurrenceBinding::OccurrenceIsKernelName => { + TypeDeclReferenceRoute::RouteKernelMint + } + TypeDeclOccurrenceBinding::OccurrenceImported { identity: _, .. } => { + TypeDeclReferenceRoute::RouteReferencingModuleImport + } + TypeDeclOccurrenceBinding::OccurrenceUndecided => { + TypeDeclReferenceRoute::RouteLeafSpelling + } + } + } +} + +pub fn type_decl_occurrence_identity( + index: Rc, + leaf: String, + reference: Rc, +) -> Option { + match (*type_decl_occurrence_binding(index.clone(), leaf.clone(), reference.clone())).clone() { + TypeDeclOccurrenceBinding::OccurrenceDeclaredHere { + identity: identity, .. + } => Some(identity.clone()), + TypeDeclOccurrenceBinding::OccurrenceIsKernelName => { + type_decl_kernel_mint_declarer(index.clone(), leaf.clone()) + } + TypeDeclOccurrenceBinding::OccurrenceImported { + identity: identity, .. + } => Some(identity.clone()), + TypeDeclOccurrenceBinding::OccurrenceUndecided => std::option::Option::None, + } +} + +pub fn type_decl_occurrence_binding( + index: Rc, + leaf: String, + reference: Rc, +) -> Rc { + match (*crate::v1_compiler_infer_env::bare_occurrence_binding( + index.qualified_names.clone(), + leaf.clone(), + reference.clone(), + )) + .clone() + { + BareOccurrenceBinding::BareOccurrenceDeclaredInItsFile { + declaration: decl, .. + } => match type_decl_identity_of_declaration(index.clone(), decl.clone()) { + Some(identity) => Rc::new(TypeDeclOccurrenceBinding::OccurrenceDeclaredHere { + identity: identity.clone(), + }), + std::option::Option::None => Rc::new(TypeDeclOccurrenceBinding::OccurrenceUndecided), + }, + BareOccurrenceBinding::BareOccurrenceImportedByName { + module_path: from_module, + declaration: decl, + .. + } => match type_decl_identity_of_declaration(index.clone(), decl.clone()) { + Some(identity) => Rc::new(TypeDeclOccurrenceBinding::OccurrenceImported { + identity: identity.clone(), + }), + std::option::Option::None => { + let imported = type_decl_identity(from_module.clone(), leaf.clone()); + match v1_rt::map_get(&index.by_identity.clone(), imported.clone()) { + Some(_) => Rc::new(TypeDeclOccurrenceBinding::OccurrenceImported { + identity: imported.clone(), + }), + std::option::Option::None => { + Rc::new(TypeDeclOccurrenceBinding::OccurrenceUndecided) + } + } + } + }, + BareOccurrenceBinding::BareOccurrenceIsKernelName => { + Rc::new(TypeDeclOccurrenceBinding::OccurrenceIsKernelName) + } + BareOccurrenceBinding::BareOccurrenceUndecided => { + Rc::new(TypeDeclOccurrenceBinding::OccurrenceUndecided) + } + } +} + +pub fn type_decl_identity_of_declaration( + index: Rc, + decl: Rc, +) -> Option { + match decl.ident_span.clone() { + Some(sp) => v1_rt::map_get( + &index.identity_by_declaring_span.clone(), + declaring_span_key(sp.clone()), + ), + std::option::Option::None => std::option::Option::None, + } +} + pub fn type_decl_index_with_qualified_names( index: Rc, qualified_names: Rc, @@ -535,53 +880,12 @@ pub fn type_decl_index_with_qualified_names( pub fn referencing_module_declarer_route_dissolves_on() -> Rc { thread_local! { static CACHED: Rc = { - crate::std_dissolution::unbound_dissolution("RouteReferencingModuleDeclarer and RouteQualifiedSpelling dissolve when the type environment's declaration bodies carry Node.declaration on every member type reference, stamped by v1.compiler.infer_resolve reference_with_declaration in the DECLARING module's scope, so a bare reference resolved through lookup_type_for hands the emitter stamped members: v1.tests.claim.carrier_realization_census reports zero emitter_decl_route referencing_module_declarer or qualified_spelling rows over the self-host and dag closures. Stamping one declaration, or one closure, is not that capability. Then both arms, type_decl_referencing_module_declarer and type_decl_qualifier_declarer are deleted and such a reference refuses unless carried.".to_string()) + crate::std_dissolution::unbound_dissolution("RouteReferencingModuleDeclarer, RouteReferencingModuleImport, RouteQualifiedSpelling and RouteKernelMint dissolve when the type environment's declaration bodies carry Node.declaration on every member type reference, stamped by v1.compiler.infer_resolve reference_with_declaration in the DECLARING module's scope, so a bare reference resolved through lookup_type_for hands the emitter stamped members: v1.tests.claim.carrier_realization_census reports zero emitter_decl_route referencing_module_declarer, referencing_module_import, qualified_spelling or kernel_mint rows over the self-host and dag closures. Stamping one declaration, or one closure, is not that capability. Then type_decl_occurrence_binding and type_decl_qualifier_declarer are deleted and such a reference refuses unless carried.".to_string()) }; } CACHED.with(|c: &Rc| c.clone()) } -pub fn type_decl_referencing_module_declarer( - index: Rc, - leaf: String, - reference: Rc, -) -> Option { - { - let local = Rc::new({ - let mut __result = Vec::new(); - for identity in type_decl_identities_of_leaf(index.clone(), leaf.clone()) - .iter() - .cloned() - { - if match v1_rt::map_get(&index.by_identity.clone(), identity.clone()) { - Some(decl) => { - (decl.span.clone().file.clone() == reference.span.clone().file.clone()) - } - std::option::Option::None => false, - } { - __result.push(identity); - } - } - __result - }); - if (local - .iter() - .cloned() - .fold(0, |n: i64, _identity: String| v1_rt::int_add(n, 1)) - == 1) - { - local - .iter() - .cloned() - .fold(std::option::Option::None, |acc: _, identity: String| { - Some(identity.clone()) - }) - } else { - std::option::Option::None - } - } -} - pub fn resolve_type_decl_reference( index: Rc, type_expr: Rc, @@ -602,6 +906,10 @@ pub fn type_decl_routed_resolution_label(routed: Rc) - "referencing_module_declarer".to_string() } TypeDeclReferenceRoute::RouteQualifiedSpelling => "qualified_spelling".to_string(), + TypeDeclReferenceRoute::RouteReferencingModuleImport => { + "referencing_module_import".to_string() + } + TypeDeclReferenceRoute::RouteKernelMint => "kernel_mint".to_string(), TypeDeclReferenceRoute::RouteLeafSpelling => "leaf_spelling".to_string(), }; match (*routed.resolution.clone()).clone() { @@ -628,7 +936,7 @@ pub fn type_decl_routed_resolution_label(routed: Rc) - #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct EmitGraphInfo { - pub type_summaries: Rc>>, + pub type_summaries: Rc, pub type_decl_items: Rc, pub data_variant_wire_spellings: Rc>>, pub fn_decl_items: Rc>>, @@ -654,7 +962,7 @@ pub struct EmitGraphInfo { #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct EmitInfoBuildState { - pub type_summaries: Rc>>, + pub type_summaries: Rc, pub type_decl_items: Rc, pub fn_decl_items: Rc>>, pub structural_alias_fn_surface_names: Rc>>>, @@ -664,7 +972,7 @@ pub struct EmitInfoBuildState { pub fn empty_emit_graph_info() -> Rc { Rc::new(EmitGraphInfo { item_leaf_owner_modules: v1_rt::rc_empty_map::>(), - type_summaries: v1_rt::rc_empty_map::>(), + type_summaries: empty_type_summary_index(), type_decl_items: empty_type_decl_index(), data_variant_wire_spellings: v1_rt::rc_empty_map::>(), fn_decl_items: v1_rt::rc_empty_map::>(), @@ -804,7 +1112,80 @@ pub fn lookup_emit_type_summary( emit_info: Rc, type_name: String, ) -> Option> { - v1_rt::map_get(&emit_info.type_summaries.clone(), type_name.clone()) + type_summary_decided(emit_info.type_summaries.clone(), type_name.clone()) +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum TypeSummaryQuestion { + QuestionDecided { value: bool }, + QuestionNameAmbiguous { leaf: String }, + QuestionNotDeclared, +} + +pub fn type_summary_answer( + index: Rc, + key: String, + question: impl Fn(Rc) -> bool + Clone, +) -> Rc { + match (*type_summary_lookup(index.clone(), key.clone())).clone() { + TypeSummaryLookup::TypeSummaryFound { + summary: summary, .. + } => Rc::new(TypeSummaryQuestion::QuestionDecided { + value: question(summary.clone()), + }), + TypeSummaryLookup::TypeSummaryNotDeclared => { + Rc::new(TypeSummaryQuestion::QuestionNotDeclared) + } + TypeSummaryLookup::TypeSummaryLeafAmbiguous { leaf: leaf, .. } => { + let answers = type_summary_keys_of_leaf(index.clone(), leaf.clone()) + .iter() + .cloned() + .fold( + Rc::new(vec![]), + |acc: Rc>, k: String| match v1_rt::map_get( + &index.by_key.clone(), + k.clone(), + ) { + Some(summary) => { + v1_rt::rc_list_push(acc.clone(), question(summary.clone())) + } + std::option::Option::None => acc.clone(), + }, + ); + if ((answers.clone().len() as i64) == 0) { + Rc::new(TypeSummaryQuestion::QuestionNotDeclared) + } else { + if { + let mut __all = true; + for a in answers.iter().cloned() { + if !(a.clone()) { + __all = false; + break; + } + } + __all + } { + Rc::new(TypeSummaryQuestion::QuestionDecided { value: true }) + } else { + if { + let mut __all = true; + for a in answers.iter().cloned() { + if !(!a.clone()) { + __all = false; + break; + } + } + __all + } { + Rc::new(TypeSummaryQuestion::QuestionDecided { value: false }) + } else { + Rc::new(TypeSummaryQuestion::QuestionNameAmbiguous { leaf: leaf.clone() }) + } + } + } + } + } } pub fn emit_graph_records_type_decl( @@ -826,10 +1207,8 @@ pub fn emit_graph_records_fn_decl(item: Rc) -> bool { (item.module_item_kind.clone() == ParsedModuleItemKind::ModuleItemFunction) } -pub fn derive_variant_to_enum( - type_summaries: Rc>>, -) -> Rc> { - Rc::new(v1_rt::map_values(&type_summaries)) +pub fn derive_variant_to_enum(type_summaries: Rc) -> Rc> { + type_summary_values(type_summaries.clone()) .iter() .cloned() .fold( @@ -855,7 +1234,7 @@ pub fn derive_variant_to_enum( std::option::Option::None => v1_rt::rc_map_insert( inner.clone(), vn.clone(), - summary.name.clone(), + summary.key.clone(), ), }, ) @@ -865,13 +1244,10 @@ pub fn derive_variant_to_enum( ) } -pub fn is_known_variant( - type_summaries: Rc>>, - name: String, -) -> bool { +pub fn is_known_variant(type_summaries: Rc, name: String) -> bool { { let mut __found = false; - for summary in Rc::new(v1_rt::map_values(&type_summaries)).iter().cloned() { + for summary in type_summary_values(type_summaries.clone()).iter().cloned() { if match (*summary.repr.clone()).clone() { TypeRepr::EnumRepr { unit_only: _, .. } => { crate::v1_compiler_infer_types::emit_map_has( @@ -889,54 +1265,89 @@ pub fn is_known_variant( } } +pub fn summary_is_enum_with_variant(summary: Rc, variant_name: String) -> bool { + match (*summary.repr.clone()).clone() { + TypeRepr::EnumRepr { unit_only: _, .. } => crate::v1_compiler_infer_types::emit_map_has( + summary.variant_name_set.clone(), + variant_name.clone(), + ), + _ => false, + } +} + +pub fn summary_is_enum(summary: Rc) -> bool { + match (*summary.repr.clone()).clone() { + TypeRepr::EnumRepr { unit_only: _, .. } => true, + _ => false, + } +} + pub fn variant_belongs_to_enum( - type_summaries: Rc>>, + type_summaries: Rc, variant_name: String, enum_name: String, -) -> bool { - match v1_rt::map_get(&type_summaries, enum_name.clone()) { - Some(summary) => match (*summary.repr.clone()).clone() { - TypeRepr::EnumRepr { unit_only: _, .. } => { - crate::v1_compiler_infer_types::emit_map_has( - summary.variant_name_set.clone(), - variant_name.clone(), - ) - } - _ => false, - }, - std::option::Option::None => false, - } +) -> Rc { + type_summary_answer(type_summaries.clone(), enum_name.clone(), |summary| { + summary_is_enum_with_variant(summary.clone(), variant_name.clone()) + }) } pub fn is_enum_in_summaries( - type_summaries: Rc>>, + type_summaries: Rc, type_name: String, -) -> bool { - match v1_rt::map_get(&type_summaries, type_name.clone()) { - Some(summary) => match (*summary.repr.clone()).clone() { - TypeRepr::EnumRepr { unit_only: _, .. } => true, - _ => false, - }, - std::option::Option::None => false, - } +) -> Rc { + type_summary_answer(type_summaries.clone(), type_name.clone(), |summary| { + summary_is_enum(summary.clone()) + }) } pub fn find_variant_parent( - type_summaries: Rc>>, + type_summaries: Rc, variant_name: String, scope_enums: Rc>, ) -> Option { - Rc::new({ - let mut __result = Vec::new(); + if { + let mut __found = false; for en in scope_enums.iter().cloned() { - if variant_belongs_to_enum(type_summaries.clone(), variant_name.clone(), en.clone()) { - __result.push(en); + if match (*variant_belongs_to_enum( + type_summaries.clone(), + variant_name.clone(), + en.clone(), + )) + .clone() + { + TypeSummaryQuestion::QuestionNameAmbiguous { leaf: _, .. } => true, + _ => false, + } { + __found = true; + break; } } - __result - }) - .first() - .cloned() + __found + } { + std::option::Option::None + } else { + Rc::new({ + let mut __result = Vec::new(); + for en in scope_enums.iter().cloned() { + if match (*variant_belongs_to_enum( + type_summaries.clone(), + variant_name.clone(), + en.clone(), + )) + .clone() + { + TypeSummaryQuestion::QuestionDecided { value: v, .. } => v.clone(), + _ => false, + } { + __result.push(en); + } + } + __result + }) + .first() + .cloned() + } } pub fn field_value_shape_from_type_node(type_node: Rc) -> FieldValueShape { @@ -1264,6 +1675,7 @@ pub fn build_type_summary( source_indices.clone(), item.clone(), ), + key: "".to_string(), repr: Rc::new(TypeRepr::StructRepr), field_summaries: build_struct_field_summaries( item.clone(), @@ -1293,6 +1705,7 @@ pub fn build_type_summary( source_indices.clone(), item.clone(), ), + key: "".to_string(), repr: Rc::new(TypeRepr::EnumRepr { unit_only: unit_only.clone(), }), @@ -1380,12 +1793,22 @@ pub struct FnReachRound { pub grew: bool, } +pub fn fn_reach_target_keys(index: Rc, target: String) -> Rc> { + match v1_rt::map_get(&index.by_key.clone(), target.clone()) { + Some(_) => Rc::new(vec![target.clone()]), + std::option::Option::None => v1_rt::concat( + type_summary_keys_of_leaf(index.clone(), target.clone()), + Rc::new(vec![target.clone()]), + ), + } +} + pub fn fn_reach_holds_directly( name: String, - summaries: Rc>>, + summaries: Rc, structural_alias_direct_fn_names: Rc>, ) -> bool { - match v1_rt::map_get(&summaries, name.clone()) { + match v1_rt::map_get(&summaries.by_key.clone(), name.clone()) { Some(s) => s.has_fn_fields.clone(), std::option::Option::None => { v1_rt::set_contains(&structural_alias_direct_fn_names, name.clone()) @@ -1395,26 +1818,34 @@ pub fn fn_reach_holds_directly( pub fn fn_reach_targets( name: String, - summaries: Rc>>, + summaries: Rc, structural_alias_fn_surface_names: Rc>>>, ) -> Rc> { - match v1_rt::map_get(&summaries, name.clone()) { - Some(s) => v1_rt::concat( - Rc::new(v1_rt::map_values(&s.field_type_map.clone())), - s.field_import_surface_names.clone(), - ), - std::option::Option::None => { - match v1_rt::map_get(&structural_alias_fn_surface_names, name.clone()) { - Some(targets) => targets.clone(), - std::option::Option::None => Rc::new(vec![]), + { + let spelled = match v1_rt::map_get(&summaries.by_key.clone(), name.clone()) { + Some(s) => v1_rt::concat( + Rc::new(v1_rt::map_values(&s.field_type_map.clone())), + s.field_import_surface_names.clone(), + ), + std::option::Option::None => { + match v1_rt::map_get(&structural_alias_fn_surface_names, name.clone()) { + Some(targets) => targets.clone(), + std::option::Option::None => Rc::new(vec![]), + } } - } + }; + spelled + .iter() + .cloned() + .fold(Rc::new(vec![]), |acc: Rc>, t: String| { + v1_rt::concat(acc, fn_reach_target_keys(summaries.clone(), t.clone())) + }) } } pub fn fn_reaching_names_fixpoint( mut __tco_loop_candidates: Rc>, - mut __tco_loop_summaries: Rc>>, + mut __tco_loop_summaries: Rc, mut __tco_loop_structural_alias_fn_surface_names: Rc>>>, mut __tco_loop_structural_alias_direct_fn_names: Rc>, mut __tco_loop_reached: Rc>, @@ -1497,13 +1928,13 @@ pub fn fn_reaching_names_fixpoint( } pub fn fn_reaching_names( - summaries: Rc>>, + summaries: Rc, structural_alias_fn_surface_names: Rc>>>, structural_alias_direct_fn_names: Rc>, ) -> Rc> { fn_reaching_names_fixpoint( v1_rt::concat( - Rc::new(v1_rt::map_keys(&summaries)), + Rc::new(v1_rt::map_keys(&summaries.by_key.clone())), Rc::new(v1_rt::map_keys(&structural_alias_fn_surface_names)), ), summaries.clone(), @@ -1514,45 +1945,56 @@ pub fn fn_reaching_names( } pub fn close_fn_fields( - summaries: Rc>>, + summaries: Rc, structural_alias_fn_surface_names: Rc>>>, structural_alias_direct_fn_names: Rc>, -) -> Rc>> { +) -> Rc { { let reaching = fn_reaching_names( summaries.clone(), structural_alias_fn_surface_names.clone(), structural_alias_direct_fn_names.clone(), ); - Rc::new(v1_rt::map_keys(&summaries)).iter().cloned().fold( - summaries.clone(), - |acc: Rc>>, name: String| match v1_rt::map_get( - &summaries, - name.clone(), - ) { - Some(s) => { - if (!s.has_fn_fields.clone() && v1_rt::set_contains(&reaching, name.clone())) { - v1_rt::rc_map_insert( - acc.clone(), - name.clone(), - Rc::new(TypeSummary { - name: s.name.clone(), - repr: s.repr.clone(), - field_summaries: s.field_summaries.clone(), - field_type_map: s.field_type_map.clone(), - field_import_surface_names: s.field_import_surface_names.clone(), - variant_name_set: s.variant_name_set.clone(), - generic_param_names: s.generic_param_names.clone(), - has_fn_fields: true, - }), - ) - } else { - acc.clone() - } - } - std::option::Option::None => acc.clone(), - }, - ) + Rc::new(TypeSummaryIndex { + by_key: Rc::new(v1_rt::map_keys(&summaries.by_key.clone())) + .iter() + .cloned() + .fold( + summaries.by_key.clone(), + |acc: Rc>>, key: String| match v1_rt::map_get( + &summaries.by_key.clone(), + key.clone(), + ) { + Some(s) => { + if (!s.has_fn_fields.clone() + && v1_rt::set_contains(&reaching, key.clone())) + { + v1_rt::rc_map_insert( + acc.clone(), + key.clone(), + Rc::new(TypeSummary { + name: s.name.clone(), + key: s.key.clone(), + repr: s.repr.clone(), + field_summaries: s.field_summaries.clone(), + field_type_map: s.field_type_map.clone(), + field_import_surface_names: s + .field_import_surface_names + .clone(), + variant_name_set: s.variant_name_set.clone(), + generic_param_names: s.generic_param_names.clone(), + has_fn_fields: true, + }), + ) + } else { + acc.clone() + } + } + std::option::Option::None => acc.clone(), + }, + ), + keys_by_leaf: summaries.keys_by_leaf.clone(), + }) } } @@ -1651,13 +2093,15 @@ pub fn add_emit_item_summary( state.clone() }; match build_type_summary(item.clone(), source_indices.clone()) { - Some(summary) => { + Some(built) => { + let key = type_decl_identity(module_name.clone(), built.name.clone()); + let summary = type_summary_with_key(built.clone(), key.clone()); let with_variants = match (*summary.repr.clone()).clone() { TypeRepr::EnumRepr { unit_only: _, .. } => { item.children.clone().iter().cloned().fold( state.type_summaries.clone(), - |acc: Rc>>, variant: Rc| { + |acc: Rc, variant: Rc| { if ((variant.children.clone().len() as i64) > 0) { { let v_has_fn = { @@ -1688,15 +2132,19 @@ pub fn add_emit_item_summary( summary.name.clone(), vname.clone(), ); + let variant_key = + variant_summary_key(key.clone(), vname.clone()); let variant_field_types = build_field_type_map( variant.children.clone(), source_indices.clone(), ); - v1_rt::rc_map_insert( + type_summary_index_insert( acc.clone(), + variant_key.clone(), qualified_vname.clone(), Rc::new(TypeSummary { name: qualified_vname.clone(), + key: variant_key.clone(), repr: Rc::new(TypeRepr::StructRepr), field_summaries: build_struct_field_summaries( variant.clone(), @@ -1726,8 +2174,9 @@ pub fn add_emit_item_summary( } _ => state.type_summaries.clone(), }; - let next_summaries = v1_rt::rc_map_insert( + let next_summaries = type_summary_index_insert( with_variants.clone(), + key.clone(), summary.name.clone(), summary.clone(), ); @@ -1748,6 +2197,20 @@ pub fn add_emit_item_summary( } } +pub fn type_summary_with_key(summary: Rc, key: String) -> Rc { + Rc::new(TypeSummary { + name: summary.name.clone(), + key: key.clone(), + repr: summary.repr.clone(), + field_summaries: summary.field_summaries.clone(), + field_type_map: summary.field_type_map.clone(), + field_import_surface_names: summary.field_import_surface_names.clone(), + variant_name_set: summary.variant_name_set.clone(), + generic_param_names: summary.generic_param_names.clone(), + has_fn_fields: summary.has_fn_fields.clone(), + }) +} + pub fn emit_dependency_registration_dissolve_on_note() -> Rc { thread_local! { static CACHED: Rc = { @@ -1768,4 +2231,8 @@ pub struct RouteReferencingModuleDeclarer; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct RouteQualifiedSpelling; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct RouteReferencingModuleImport; +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct RouteKernelMint; +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct RouteLeafSpelling; diff --git a/src/v1/stage0/src/v1_compiler_infer_env.rs b/src/v1/stage0/src/v1_compiler_infer_env.rs index 3732f70645d..6b433a6a620 100644 --- a/src/v1/stage0/src/v1_compiler_infer_env.rs +++ b/src/v1/stage0/src/v1_compiler_infer_env.rs @@ -1,6 +1,7 @@ // Generated by v1 compiler -- do not edit. // Source module: v1.compiler.infer_env +use self::BareOccurrenceBinding::*; use self::GlobalBareLookupState::*; use self::TypeNodeDeclarationReading::*; use self::TypeNodeUnidentifiedCause::*; @@ -351,6 +352,8 @@ pub struct SymbolIndex { pub services: Rc>>, pub transparent_alias_rep: Rc>, pub type_head_exposures: Rc>>, + pub file_modules: Rc>, + pub module_named_imports: Rc>>>, } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -365,6 +368,8 @@ pub fn empty_symbol_index() -> Rc { services: v1_rt::rc_empty_map::>(), transparent_alias_rep: v1_rt::rc_empty_map::(), type_head_exposures: v1_rt::rc_empty_map::>(), + file_modules: v1_rt::rc_empty_map::(), + module_named_imports: v1_rt::rc_empty_map::>>(), }) } @@ -395,6 +400,210 @@ pub fn symbol_index_lookup(index: Rc, qualified_name: String) -> Op v1_rt::map_get(&index.entries.clone(), qualified_name.clone()) } +pub fn overlay_skips_kernel_name(name: String) -> bool { + (((((crate::std_types::is_kernel_type(name.clone()) + || crate::std_types::is_container_type(name.clone())) + || (name.clone() == "Unit".to_string())) + || (name.clone() == "Optional".to_string())) + || (name.clone() == "Present".to_string())) + || (name.clone() == "Absent".to_string())) +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum BareOccurrenceBinding { + BareOccurrenceDeclaredInItsFile { + declaration: Rc, + }, + BareOccurrenceImportedByName { + module_path: String, + declaration: Rc, + }, + BareOccurrenceIsKernelName, + BareOccurrenceUndecided, +} +impl BareOccurrenceBinding { + pub fn declaration(&self) -> Rc { + match self { + BareOccurrenceBinding::BareOccurrenceDeclaredInItsFile { + declaration: __val, .. + } => __val.clone(), + BareOccurrenceBinding::BareOccurrenceImportedByName { + declaration: __val, .. + } => __val.clone(), + BareOccurrenceBinding::BareOccurrenceIsKernelName => { + panic!("no declaration on unit variant") + } + BareOccurrenceBinding::BareOccurrenceUndecided => { + panic!("no declaration on unit variant") + } + } + } +} + +pub fn symbol_index_bare_declarations(index: Rc, name: String) -> Rc>> { + match v1_rt::map_get(&index.global_bare.clone(), name.clone()) + .as_deref() + .cloned() + { + Some(GlobalBareLookupState::GlobalBareUniqueBinding { binding: b, .. }) => { + Rc::new(vec![b.resolved.clone()]) + } + Some(GlobalBareLookupState::GlobalBareAmbiguousBinding { candidates: cs, .. }) => { + Rc::new({ + let mut __result = Vec::new(); + for c in cs.iter().cloned() { + __result.push(c.binding.clone().resolved.clone()); + } + __result + }) + } + std::option::Option::None => Rc::new(vec![]), + } +} + +pub fn bare_occurrence_import( + index: Rc, + name: String, + reference: Rc, +) -> Option> { + match v1_rt::map_get( + &index.file_modules.clone(), + reference.span.clone().file.clone(), + ) { + std::option::Option::None => std::option::Option::None, + Some(referencing_module) => match symbol_index_named_import_source( + index.clone(), + referencing_module.clone(), + name.clone(), + ) { + std::option::Option::None => std::option::Option::None, + Some(from_module) => Some(bare_occurrence_import_terminal( + index.clone(), + from_module.clone(), + name.clone(), + 16, + )), + }, + } +} + +pub fn symbol_index_named_import_source( + index: Rc, + module_path: String, + name: String, +) -> Option { + match v1_rt::map_get(&index.module_named_imports.clone(), module_path.clone()) { + std::option::Option::None => std::option::Option::None, + Some(named) => v1_rt::map_get(&named, name.clone()), + } +} + +pub fn bare_occurrence_import_terminal( + mut __tco_loop_index: Rc, + mut __tco_loop_module_path: String, + mut __tco_loop_name: String, + mut __tco_loop_fuel: i64, +) -> Rc { + loop { + #[allow(unused_mut)] + let mut index = __tco_loop_index; + #[allow(unused_mut)] + let mut module_path = __tco_loop_module_path; + #[allow(unused_mut)] + let mut name = __tco_loop_name; + #[allow(unused_mut)] + let mut fuel = __tco_loop_fuel; + if (fuel.clone() == 0) { + break Rc::new(BareOccurrenceBinding::BareOccurrenceUndecided); + } else { + match symbol_index_named_import_source(index.clone(), module_path.clone(), name.clone()) + { + Some(next) => { + let __tco_0 = index; + let __tco_1 = next.clone(); + let __tco_2 = name; + let __tco_3 = v1_rt::int_sub(fuel, 1); + __tco_loop_index = __tco_0; + __tco_loop_module_path = __tco_1; + __tco_loop_name = __tco_2; + __tco_loop_fuel = __tco_3; + continue; + } + std::option::Option::None => { + match symbol_index_lookup( + index.clone(), + v1_rt::concat( + v1_rt::concat(module_path.clone(), ".".to_string()), + name.clone(), + ), + ) { + Some(decl) => { + break Rc::new(BareOccurrenceBinding::BareOccurrenceImportedByName { + module_path: module_path.clone(), + declaration: decl.clone(), + }); + } + std::option::Option::None => { + break Rc::new(BareOccurrenceBinding::BareOccurrenceUndecided); + } + } + } + } + } + } +} + +pub fn bare_occurrence_binding( + index: Rc, + name: String, + reference: Rc, +) -> Rc { + { + let local = Rc::new({ + let mut __result = Vec::new(); + for d in symbol_index_bare_declarations(index.clone(), name.clone()) + .iter() + .cloned() + { + if (d.span.clone().file.clone() == reference.span.clone().file.clone()) { + __result.push(d); + } + } + __result + }); + let local_count = local + .iter() + .cloned() + .fold(0, |n: i64, _d: Rc| v1_rt::int_add(n, 1)); + if (local_count.clone() == 1) { + local.iter().cloned().fold( + Rc::new(BareOccurrenceBinding::BareOccurrenceUndecided), + |acc: Rc, d: Rc| { + Rc::new(BareOccurrenceBinding::BareOccurrenceDeclaredInItsFile { + declaration: d.clone(), + }) + }, + ) + } else { + if (local_count.clone() > 1) { + Rc::new(BareOccurrenceBinding::BareOccurrenceUndecided) + } else { + match bare_occurrence_import(index.clone(), name.clone(), reference.clone()) { + Some(imported) => imported.clone(), + std::option::Option::None => { + if overlay_skips_kernel_name(name.clone()) { + Rc::new(BareOccurrenceBinding::BareOccurrenceIsKernelName) + } else { + Rc::new(BareOccurrenceBinding::BareOccurrenceUndecided) + } + } + } + } + } + } +} + pub fn global_bare_candidates_contain( candidates: Rc>>, resolved: Rc, @@ -493,6 +702,8 @@ pub fn symbol_index_insert( services: index.services.clone(), transparent_alias_rep: index.transparent_alias_rep.clone(), type_head_exposures: index.type_head_exposures.clone(), + file_modules: index.file_modules.clone(), + module_named_imports: index.module_named_imports.clone(), }) } @@ -518,6 +729,8 @@ pub fn symbol_index_insert_decl( services: index.services.clone(), transparent_alias_rep: index.transparent_alias_rep.clone(), type_head_exposures: index.type_head_exposures.clone(), + file_modules: index.file_modules.clone(), + module_named_imports: index.module_named_imports.clone(), }) } @@ -540,6 +753,8 @@ pub fn symbol_index_insert_service( ), transparent_alias_rep: index.transparent_alias_rep.clone(), type_head_exposures: index.type_head_exposures.clone(), + file_modules: index.file_modules.clone(), + module_named_imports: index.module_named_imports.clone(), }) } diff --git a/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs b/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs index 892eefcb3fe..ed8fa600c3e 100644 --- a/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs +++ b/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs @@ -17,9 +17,11 @@ pub use crate::v1_compiler_emit_rust::{ reference_derived_candidate_disposition, reference_derived_census, reference_derived_disposition_name, reference_derived_row_diagnostics, }; -pub use crate::v1_compiler_infer_emit_info::empty_emit_graph_info; use crate::v1_compiler_infer_emit_info::TypeRepr::EnumRepr; -pub use crate::v1_compiler_infer_emit_info::{TypeRepr, TypeSummary}; +pub use crate::v1_compiler_infer_emit_info::{ + empty_emit_graph_info, empty_type_summary_index, type_summary_index_insert, +}; +pub use crate::v1_compiler_infer_emit_info::{TypeRepr, TypeSummary, TypeSummaryIndex}; use crate::v1_compiler_infer_items::ItemKind::FnItem; pub use crate::v1_compiler_infer_items::{ItemInfo, ItemKind}; use crate::v1_rt; @@ -91,7 +93,7 @@ pub fn fixture_disposition( Rc::new(vec![]), v1_rt::rc_empty_map::>(), ), - v1_rt::rc_empty_map::>(), + crate::v1_compiler_infer_emit_info::empty_type_summary_index(), v1_rt::rc_empty_map::(), false, ), @@ -132,7 +134,7 @@ pub fn cross_module_candidate_with_export_proof_survives() -> bool { Rc::new(vec![]), v1_rt::rc_empty_map::>(), ), - v1_rt::rc_empty_map::>(), + crate::v1_compiler_infer_emit_info::empty_type_summary_index(), v1_rt::rc_empty_map::(), false, ) == Rc::new(ReferenceDerivedCandidateDisposition::CandidateSurvived { @@ -219,12 +221,14 @@ pub fn variant_arm_red_note() -> String { CACHED.with(|c: &String| c.clone()) } -pub fn fixture_variant_type_summaries() -> Rc>> { - v1_rt::rc_map_insert( - v1_rt::rc_empty_map::>(), +pub fn fixture_variant_type_summaries() -> Rc { + crate::v1_compiler_infer_emit_info::type_summary_index_insert( + crate::v1_compiler_infer_emit_info::empty_type_summary_index(), + "fixture.E".to_string(), "E".to_string(), Rc::new(TypeSummary { name: "E".to_string(), + key: "fixture.E".to_string(), repr: Rc::new(TypeRepr::EnumRepr { unit_only: true }), field_summaries: v1_rt::rc_empty_map::>(), field_type_map: v1_rt::rc_empty_map::(), @@ -257,7 +261,7 @@ pub fn known_variant_is_delegated_to_its_parent_not_registry_absent() -> bool { v1_rt::rc_map_insert( v1_rt::rc_empty_map::(), "V".to_string(), - "E".to_string(), + "fixture.E".to_string(), ), false, ) == Rc::new( @@ -276,12 +280,14 @@ pub fn ambiguous_parent_red_note() -> String { CACHED.with(|c: &String| c.clone()) } -pub fn fixture_colliding_variant_type_summaries() -> Rc>> { - v1_rt::rc_map_insert( +pub fn fixture_colliding_variant_type_summaries() -> Rc { + crate::v1_compiler_infer_emit_info::type_summary_index_insert( fixture_variant_type_summaries(), + "fixture.F".to_string(), "F".to_string(), Rc::new(TypeSummary { name: "F".to_string(), + key: "fixture.F".to_string(), repr: Rc::new(TypeRepr::EnumRepr { unit_only: true }), field_summaries: v1_rt::rc_empty_map::>(), field_type_map: v1_rt::rc_empty_map::(), @@ -338,7 +344,7 @@ pub fn a_known_variant_spelling_in_a_type_position_takes_the_registry_arm() -> b v1_rt::rc_map_insert( v1_rt::rc_empty_map::(), "V".to_string(), - "E".to_string(), + "fixture.E".to_string(), ), true, ), @@ -369,7 +375,7 @@ pub fn non_variant_name_still_answers_registry_absent() -> bool { v1_rt::rc_map_insert( v1_rt::rc_empty_map::(), "V".to_string(), - "E".to_string(), + "fixture.E".to_string(), ), false, ), diff --git a/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag b/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag index 9f6d9fcb47d..69a9e3bcc39 100644 --- a/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag +++ b/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag @@ -24,7 +24,7 @@ import v1.compiler.infer_items { ItemInfo, FnItem } import v1.std.core { ErrorNode, SourceSpan, no_span, diagnostic_to_message, is_error_diagnostic } -import v1.compiler.infer_emit_info { TypeSummary, EnumRepr, empty_emit_graph_info } +import v1.compiler.infer_emit_info { TypeSummary, TypeSummaryIndex, EnumRepr, empty_emit_graph_info, empty_type_summary_index, type_summary_index_insert } import v1.compiler.compile { SourceFile, compile_to_resolved } data reference_derived_disposition_census_witness_note: String = "THE ROUTE HALF OF THIS FILE IS ABSENT AND THE REASON IS A WALL RATHER THAN A CHOICE, stated here because it is the first thing a reader of a five-row file should know: the end-to-end pair this file was designed around -- a two-module manifest whose consumer calls a peer fn in VALUE position with no import, against a control differing by one authored import line -- was authored and DOES NOT RUN. A nested compile is not evaluable in the interpreter: compile_to_resolved over an authored source vector refuses with NoSuchField Node.ident during the nested pipeline, measured 2026-08-27 on three separate subjects. CAUSE CORRECTED 2026-09-02 (quick-crab-396): THAT SENTENCE NAMES A SYMPTOM AND NOT THE CLASS. Nested compiles are one POPULATION that constructs Nodes through helpers omitting v1.std.core Node's `ident` and then reads it; the class is that the interpreter has NO DEFAULT FOR AN OMITTED OPTIONAL FIELD and refuses on read, general to any record type -- established by a two-row probe with a positive control on a fresh type unrelated to Node, filed as the fourth form of gunbc.recurring_failure_mode state_space_conflation, which is the producer to re-derive from. This matters for what to DO: the repair the symptom suggests -- route around the nested pipeline with a host builtin, as the two instruments below do -- does not touch the cause, and the capability that would is construction supplying every declared field. That is not a property of this change; it is why the two nested-compile instruments the corpus already has (gunbc.compile_diagnostic_census and tools.multi_module_compile_fixture) both route through a HOST BUILTIN rather than calling the pipeline from .dag. The rows are not retained in a form that cannot execute, because a probe that always errors is not a red -- it is an inert artifact that would be counted as coverage. NEXT-RUNG TRIGGER FOR THE ROUTE: a nested-compile builtin returning the resolved graph, the shape tools.multi_module_compile_fixture already has, widened to carry the emitter reference-derived rows.\n\nWHERE THIS RUNS, STATED FIRST AND WITHOUT FLATTERY. THIS WITNESS IS NOT RUN BY CI. gunbc.ci_layer_roots witness_discovery_scan_dirs is [dag/test/claim, src/v2/test/claim/manual, src/v2/test/claim/emit] -- src/v1/tests/claim is not among them -- and the required run invokes claim_executor with --source-root dag --source-root src/v2, which could not resolve this file's import of v1.compiler.emit_rust even if discovery reached it. The scoped batch that once ran this directory died in the 2026-08-15 floor cut; gunbc.ci_layer_roots v1_claim_scoped_witness_batch_deleted_note records that and states the entries here have no executing consumer. The roster its sibling checkpoint_identity_keying_witness_test claims to be enrolled in, v1_claim_scoped_witness_entries, is not declared anywhere in dag/gunbc/ci/ci_layer_roots.dag -- verified by grep in both directions rather than taken from the note. THE FIVE ROWS BELOW WERE RUN DIRECTLY ON 2026-08-27 AND ALL FIVE PASS. Direct execution is evidence the assertions HOLD, never evidence that CI runs them, and conflating those two is the rung inflation this directory has now recorded twice.\n\nWHAT THE SUBJECT IS. Since PR 6848 a cross-module name resolves whether or not it is imported. At TYPE positions the resolver says so advisorily (UnlistedImportUse, is_error_diagnostic false); at VALUE positions it says nothing at all, and the emitter silently synthesizes the use-line the author did not write. That synthesis is unchanged here and deliberately so. What changed is that the per-candidate decision behind it stopped being an inline flat_map whose three non-surviving arms all returned the empty list, and became a four-armed coproduct one census can count.\n\nWHY BOTH HALVES ARE HERE. The four unit rows discriminate the DECISION: each names a distinct arm, and two of them differ ONLY in whether the provider's export set proves the symbol, so no constant, disabled mechanism or name-keyed rule satisfies them together. The end-to-end rows discriminate the CENSUS ROUTE: a two-module manifest compiled through compile_to_resolved, whose consumer references a peer's fn in VALUE position with no import, against a control differing by exactly one authored import line. The unlisted arm must produce a survived row naming peer_answer; the control must produce no row for that name at all, because an already-provided name never reaches the decision. Neither can pass vacuously -- a census that always reported zero fails the first, and one that reported every reference fails the second.\n\nTHE RED IS AUTHORABLE AT THE FIXTURE BOUNDARY, which is what makes this a probe rather than a decoration. No Accepted corpus module can be relied on to hold a value-position unlisted use on demand, but a fixture manifest can author one directly, and this file does. DESIGN 4b: a check whose RED cannot be produced anywhere it runs is permanently green by construction and worse than absent, because it gets cited as coverage. What this file lacks is a RUNNER, not a reachable red.\n\nWHAT THIS DOES NOT ESTABLISH. Nothing about the SIZE of the live population -- these are fixtures; NO PRODUCER FOR A REAL FIGURE EXISTS YET, and this file does not name one: the only route from .dag to a corpus census is a nested compile, which the interpreter refuses, so any figure quoted today names nothing that can produce it. And nothing about the names the census never sees: a candidate already provided by an authored import, the prelude, a carrier use-line or the module's own declarations is filtered before the decision, so every count is a LOWER BOUND and the gap is unmeasured. Quote it as at least N.\n\nNEXT-RUNG TRIGGER FOR THIS FILE'S EVIDENCE, which is NOT the same trigger as the class's and must not be folded into it: one prepared subject spanning dag, src/v1 and src/v2 -- the restoration gunbc.ci_layer_roots already names for the deleted batch -- at which point these rows execute and this first paragraph deletes. The CLASS's own trigger (the value-position case joining the fail-closed wall, retiring the census and the synthesis together) lives on v1.compiler.emit_rust reference_derived_census_rung_note. Either can land first; neither closes the other." @@ -60,7 +60,7 @@ fn fixture_disposition(registry: Map, export_sets: Map Bool { typed_modules: [], source_indices: empty_map(), module_index: build_module_index(modules: [], leaf_owner_modules: empty_map()), - type_summaries: empty_map(), + type_summaries: empty_type_summary_index(), variant_to_enum: empty_map(), in_type_position: false ) == CandidateSurvived { provider_module: "fixture.provider" } @@ -119,9 +119,10 @@ test fn census_counts_each_arm_separately() -> Bool { data variant_arm_red_note: String = "THE DISCRIMINATING RED FOR THE FIFTH ARM, and it is the one this file most needs. Before the arm existed a bare variant name reached the registry lookup, missed, and answered registry-absent -- so the fixture below is RED against the four-arm classifier and green against the five-arm one, which is what makes it evidence rather than decoration. The positive control beside it is the census row above: a name that is NOT a known variant still answers registry-absent, so the arm narrows the class rather than emptying it." -fn fixture_variant_type_summaries() -> Map { - map_insert(empty_map(), "E", TypeSummary { +fn fixture_variant_type_summaries() -> TypeSummaryIndex { + type_summary_index_insert(index: empty_type_summary_index(), key: "fixture.E", leaf: "E", summary: TypeSummary { name: "E", + key: "fixture.E", repr: EnumRepr { unit_only: true }, field_summaries: empty_map(), field_type_map: empty_map(), @@ -143,16 +144,17 @@ test fn known_variant_is_delegated_to_its_parent_not_registry_absent() -> Bool { source_indices: empty_map(), module_index: build_module_index(modules: [], leaf_owner_modules: empty_map()), type_summaries: fixture_variant_type_summaries(), - variant_to_enum: map_insert(empty_map(), "V", "E"), + variant_to_enum: map_insert(empty_map(), "V", "fixture.E"), in_type_position: false ) == CandidateVariantDelegatedToParent { parent_enum: "E" } } data ambiguous_parent_red_note: String = "THE REACHABLE HALF of the unresolved-parent arm, and the reason it is not merely a tidier name. derive_variant_to_enum inserts the EMPTY STRING as the parent when one variant name appears in two enums, so the lookup answers Present with a parent naming nothing. Without this arm that produced CandidateVariantDelegatedToParent { parent_enum: \"\" } -- a delegation to no one, wearing the payload that was supposed to make delegation honest. This fixture authors the collision directly and is RED against the arm-less form." -fn fixture_colliding_variant_type_summaries() -> Map { - map_insert(fixture_variant_type_summaries(), "F", TypeSummary { +fn fixture_colliding_variant_type_summaries() -> TypeSummaryIndex { + type_summary_index_insert(index: fixture_variant_type_summaries(), key: "fixture.F", leaf: "F", summary: TypeSummary { name: "F", + key: "fixture.F", repr: EnumRepr { unit_only: true }, field_summaries: empty_map(), field_type_map: empty_map(), @@ -193,7 +195,7 @@ test fn a_known_variant_spelling_in_a_type_position_takes_the_registry_arm() -> source_indices: empty_map(), module_index: build_module_index(modules: [], leaf_owner_modules: empty_map()), type_summaries: fixture_variant_type_summaries(), - variant_to_enum: map_insert(empty_map(), "V", "E"), + variant_to_enum: map_insert(empty_map(), "V", "fixture.E"), in_type_position: true )) == "registry-absent" } @@ -213,7 +215,7 @@ test fn non_variant_name_still_answers_registry_absent() -> Bool { source_indices: empty_map(), module_index: build_module_index(modules: [], leaf_owner_modules: empty_map()), type_summaries: fixture_variant_type_summaries(), - variant_to_enum: map_insert(empty_map(), "V", "E"), + variant_to_enum: map_insert(empty_map(), "V", "fixture.E"), in_type_position: false )) == "registry-absent" } diff --git a/src/v1/tests/src/anonymous_record_struct_resolution_test.rs b/src/v1/tests/src/anonymous_record_struct_resolution_test.rs index f999ea14d5e..c18b1361a19 100644 --- a/src/v1/tests/src/anonymous_record_struct_resolution_test.rs +++ b/src/v1/tests/src/anonymous_record_struct_resolution_test.rs @@ -3,7 +3,7 @@ use std::rc::Rc; use v1_compiler::v1_compiler_emit_rust::{ anonymous_record_struct_candidates, find_struct_name_by_fields, }; -use v1_compiler::v1_compiler_infer_emit_info::{TypeRepr, TypeSummary}; +use v1_compiler::v1_compiler_infer_emit_info::{TypeRepr, TypeSummary, TypeSummaryIndex}; fn summary(name: &str, fields: &[(&str, &str)]) -> Rc { let mut field_type_map = HashMap::new(); @@ -12,6 +12,7 @@ fn summary(name: &str, fields: &[(&str, &str)]) -> Rc { } Rc::new(TypeSummary { name: name.to_string(), + key: format!("fixture.{name}"), repr: Rc::new(TypeRepr::StructRepr), field_summaries: Rc::new(HashMap::new()), field_type_map: Rc::new(field_type_map), @@ -22,12 +23,23 @@ fn summary(name: &str, fields: &[(&str, &str)]) -> Rc { }) } -fn summaries(rows: &[Rc]) -> Rc>> { - let mut result = HashMap::new(); +// Summaries are keyed by declaring identity, with the leaf index beside them. +fn summaries(rows: &[Rc]) -> Rc { + let mut by_key = HashMap::new(); + let mut keys_by_leaf: HashMap>> = HashMap::new(); for row in rows { - result.insert(row.name.clone(), row.clone()); + by_key.insert(row.key.clone(), row.clone()); + let mut keys = keys_by_leaf + .get(&row.name) + .map(|k| (**k).clone()) + .unwrap_or_default(); + keys.push_back(row.key.clone()); + keys_by_leaf.insert(row.name.clone(), Rc::new(keys)); } - Rc::new(result) + Rc::new(TypeSummaryIndex { + by_key: Rc::new(by_key), + keys_by_leaf: Rc::new(keys_by_leaf), + }) } #[test] diff --git a/src/v2/lens/text_string_importer_census.dag b/src/v2/lens/text_string_importer_census.dag index 1e835bd51ed..71aae3ce02f 100644 --- a/src/v2/lens/text_string_importer_census.dag +++ b/src/v2/lens/text_string_importer_census.dag @@ -62,7 +62,7 @@ import std.primitives { // THE CENSUS OF `import v2.std.text { String }` IMPORTERS, AT SITE GRAIN (gunbc#12760, decision A; // method ruled by neat-boar-16 2026-09-30). v1 binds a bare `String` in these modules to the KERNEL -// host text whatever the import says (`v1.compiler.infer` `overlay_skips_kernel_name`); v2 binds it +// host text whatever the import says (`v1.compiler.infer_env` `overlay_skips_kernel_name`); v2 binds it // to the structural `FreeMonoid` the import names. The fork resolves at the importers: // HOST-USING and MIXED importers drop `String` from the import, STRUCTURAL-USING importers keep it // as `gunbc.recurring_failure_mode` `carrier_by_spelling`'s declared v1/v2 divergence. This lens