diff --git a/dag/extdeps/languages/rust/representation.dag b/dag/extdeps/languages/rust/representation.dag index 5d43e55ef37..88bb73a06f2 100644 --- a/dag/extdeps/languages/rust/representation.dag +++ b/dag/extdeps/languages/rust/representation.dag @@ -2,7 +2,7 @@ module extdeps.languages.rust.representation import std.types { List, String, Bool, NonEmptyStr } import std.coercion { TypeCheckpoint } -import std.target_representation { RepresentationSpelling, SourceTypeTargetBinding } +import std.target_representation { RepresentationSpelling, SourceTypeTargetBinding, RepresentationValue } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } @@ -113,3 +113,11 @@ fn rust_exact_type_checkpoint(binding: SourceTypeTargetBinding none } } + +// THE VALUES A REPRESENTATION HAS, spelled, where a source coproduct's arms realize onto them. Target +// facts only, naming no source declaration: the Rust Reference (types, "Boolean type") gives `bool` +// exactly two values, `true` and `false`. Which source arm means which value is the corpus's fact +// (gunbc.rust_source_type_bindings rust_source_variant_value_rows). +data rust_bool_true_value: RepresentationValue = RepresentationValue { representation: RustBool, value_spelling: "true" as NonEmptyStr } +data rust_bool_false_value: RepresentationValue = RepresentationValue { representation: RustBool, value_spelling: "false" as NonEmptyStr } +data rust_representation_values: List> = [rust_bool_true_value, rust_bool_false_value] diff --git a/dag/gunbc/observation_ci_render.dag b/dag/gunbc/observation_ci_render.dag index 9c3db7c5163..13a732cd6c7 100644 --- a/dag/gunbc/observation_ci_render.dag +++ b/dag/gunbc/observation_ci_render.dag @@ -932,6 +932,7 @@ type CiWitnessRuntimeCause | WitnessCauseTypeError | WitnessCauseCrossRepresentationEquality | WitnessCauseStringRealizationStraddle + | WitnessCauseVariantRealizationRefused | WitnessCausePoolRootContributesNothing | WitnessCausePatternMatchFailure | WitnessCauseDivisionByZero @@ -961,6 +962,7 @@ fn ci_witness_runtime_cause_token(cause: CiWitnessRuntimeCause) -> String { WitnessCauseTypeError => "type-error" WitnessCauseCrossRepresentationEquality => "cross-representation-equality" WitnessCauseStringRealizationStraddle => "string-realization-straddle" + WitnessCauseVariantRealizationRefused => "variant-realization-refused" WitnessCausePoolRootContributesNothing => "pool-root-contributes-nothing" WitnessCausePatternMatchFailure => "pattern-match-failure" WitnessCauseDivisionByZero => "division-by-zero" diff --git a/dag/gunbc/recurring_failure_mode/accepted_source_emits_uncompilable_target.dag b/dag/gunbc/recurring_failure_mode/accepted_source_emits_uncompilable_target.dag index f6c951c86c2..c79b9b9c82c 100644 --- a/dag/gunbc/recurring_failure_mode/accepted_source_emits_uncompilable_target.dag +++ b/dag/gunbc/recurring_failure_mode/accepted_source_emits_uncompilable_target.dag @@ -298,6 +298,8 @@ data accepted_source_emits_uncompilable_target: RecurringFailureMode = Recurring "OCCURRENCE, 2026-09-24 (wise-hawk-615, routed from stern-raven-24's native App Attest row gunbc#12251, whose emitted crate refused at rustc with 45 errors in three emitter classes and one runtime-library gap). Each was worked to its earliest unjustified boundary (DESIGN section 6b) rather than at the call site. (C) STRING ORDERING: `a < b` over Timestamp, an alias of String (extdeps.standards.rfc_5280 x509_validity_at, gunbc.auth.approval_capability utc_instant_before). Timestamp comparison needed no new typed ordering: the interpreter already orders Strings byte-lexicographically, so the defect was the emitter's. The boundary was the operand classifier v1.compiler.emit_rust rust_operand_realization_of_type, which filed the corpus String as OperandIdentityUnavailable although the type renderer realizes it as the host text carrier by is_host_text_carrier_type; ordering then refused by operator class while `==` on the same operand passed. Repair: std.operator_realization HostRealizationReason gains HostTextCarrier and the classifier reads the renderer's own predicate, so both answer one question once; is_string_comparison admits the four ordering operators through the same host-string seam as equality, and an ordering over an OPTIONAL String refuses at emission (the interpreter has no Null-vs-Str ordering; Option's None-first order would be fabricated). (A) PRESENT BINDING: `match opt { null => a o => b }` bound the whole Option in emitted code (E0308, E0609) while v1.compiler.infer narrows `o` to the present value. ALL THREE match renderings now read the checker's optional_scrutinee_binding_is_present over match_unguarded_absent_arm_index and emit `Some(o)` in exactly that arm, never re-deriving the narrowing: emit_typed_match_arm_strs for ordinary matches, and emit_typed_tco_match_arm for matches inside the tail-call lowering, which the native App Attest run surfaced separately (extdeps.standards.rfc_5280 read_extensions_list, the one error left after the first renderer was repaired); and emit_typed_match's String-literal re-emission (needs_string_from), where a review of this PR found the decision dropped -- there a string-literal arm over an optional scrutinee also emits `Some(ref __s)`, since a literal matches only a present value. (D) OCTETS: std.bytes bytes_octets and utf8_encode_bytes were interpreter-intercepted builtins whose .dag bodies were placeholders -- `[pure_dag_seam_unreachable()]`, a one-element list of `1 / 0`, and `s as Bytes`, a cast no Rust row realizes and which emitted a runtime panic. Both are now declared HostRealizedSeams (self-call bodies, std.primitive_projection rows, std.primitive_identity declarations with SourcePreservingOrder traversal facts, extdeps.languages.rust.emit rt_function_registry rows, v1.runtime_rust bodies); bytes_octets is typed List under the bounded_natural_arithmetic_evaluated_as_unbounded_int ruling, since UInt8 has no emitted realization that holds an octet and bytes_qualified_octets is the one boundary observing the range. Two further links surfaced by execution: a REALIZED seam's self-call was lowered by the name-keyed tail-call rewrite into a non-terminating loop (rust_host_seam_is_realized now exempts it, see host_seam_self_call_diverges_when_its_arm_is_absent), and rustc's deny-by-default unconditional_panic refused every crate reaching std.bytes because of pure_dag_seam_unreachable's constant `1 / 0`. The first cut relaxed that lint for all generated code; review 71098 refused it as widening a real check to admit one placeholder, and the placeholder was the earlier link: pure_dag_seam_unreachable is now a rostered HostRealizedSeam too, refusing in the interpreter with a typed error naming the seam and panicking by name in v1_rt, so the lint stays on. EVIDENCE: the fixture test.fixture.emitted_interpreted_parity.string_order_octets_present_binding exits 0 interpreted and requires the thirteen-field line `T F T F T 6 2962370309 97 0 989 ex none q` -- fields 1-5 string ordering, 6-7 octets, 8-9 the ordinary-match present binding, 10 the tail-call-match present binding, 11-13 the String-literal re-emission -- with a RED control that exits 1 printing the observed line; its emitted crate builds and runs to the same line. The enrolled claim module test.claim.emitter_string_order_present_binding_witness_test carries the emission half: host-string ordering over an alias, the named refusal for an ordering over a String? (which inference admits today, so the arm is reachable), and the present binding in all three match renderings. The integration consumer is `gunbc test //gunbc/instruments:native-app-attest` on gunbc#12251. RUNG unchanged at mitigatable for the class: required CI still neither emits-and-compiles a fixture closure nor executes integration targets, which is this row's existing trigger.", "OCCURRENCE, 2026-09-25 (loyal-boar-23, found by swift-bat-511 on native App Attest P2b): CALLING A LOCALLY BOUND FUNCTION VALUE. extdeps.apple.app_attest first_assertion_refusal folded a List AssertionRefusal?> and called the lambda-bound element `r()`; gunbc#12251 rewrote that one fold as a named AssertionStep sum, leaving the idiom refused everywhere else. The brief placed the defect in emit_rust's callee resolution; re-deriving the chain (DESIGN 6b) placed it three links earlier and found two more downstream. (1) INFERENCE, the earliest unjustified boundary: v1.compiler.infer child_type_node, the total read of a child position's type, returned a child's inferred slot whenever it had one, and an Arrow type node carries its RETURN type there (make_callable_type) -- so the element of List Int> was Int, a lambda parameter bound under it was not callable, and the call refused as \"function 'r' not found in scope\" in `gunbc run` as well as in emission. An Arrow child is now its own type -- landed independently by gunbc#12295 (receipted on arity_proxy_for_callability_misroutes_a_found_local) while this change was in review; this change consumes it rather than restating it. (2) INFERENCE, the list literal: a lambda's typed node carries its BODY type, and a list literal took its first element's type, so [fn() { none }] against List Int?> was typed List; where the declared element is an arrow and any element is a lambda the declared arrow is the element type, every element still judged against it. (3) EMISSION, two value positions of a lambda: a lambda literal in a list was a bare closure (E0308, every closure its own type), and is now the arrow carrier through the record-field row (rust_callable_field_value_wrap) bound at the rendered arrow by a typed let, not an `as` cast, which cuts the expectation typing Some(7) as Option (E0271); a let-bound lambda was `|x|` with no call site to type x from (E0282 at x.clone()) and is now emitted with typed parameters through emit_typed_collection_lambda, staying a bare closure so it still enters an impl Fn parameter. The call sites themselves (r(), f(v), g(v)) needed no change. EVIDENCE: test.fixture.emitted_interpreted_parity local_callable_value_calls exits 0 interpreted and its emitted crate, driven by a two-line harness over its library, prints the same line `6 8 6 7 9 0` with main returning ExitSuccess; with the expected line mutated both sides refuse (interpreter exit 1, emitted main ExitFailure carrying the observed line); on the pre-fix seed the fixture refuses at resolve. test.claim.local_callable_value_call_witness_test carries three inference controls (fold, unary fold and map lambda parameters over callable elements) and two emission controls (the list-literal carrier and the typed let), all five FAIL on the pre-fix seed and PASS here. RESIDUE, stated: an UNANNOTATED let-bound lambda (`let h = fn(x) { x * 2 }`) has no parameter type a Rust closure can be written at and still emits `|x: _|`-equivalent (E0282); a non-lambda element (a let-bound closure variable) in a List keeps its bare rendering. RUNG unchanged at mitigatable: required CI still neither emits-and-compiles a fixture closure nor runs its crate, which is this row's existing trigger.", "OCCURRENCE, 2026-09-24 (lively-koi-275, gunbc#12208 MQ-1): A FIELD BOUND UNDER A NESTED VARIANT PATTERN KEEPS ITS BOX. The `diagnostics` field of `v2.std.diagnostic` `Outcome` is a recursive Optional, so `v1.compiler.emit_rust` `needs_box_wrapping` boxes it. At a SINGLE-LEVEL arm `Accepted { value: v, diagnostics: d } =>` the emitter binds the field by `ref` and unboxes it (`let d = diagnostics.as_ref()`). Under a NESTED arm `Present { value: Accepted { value: facts, diagnostics: d } } =>` it bound the Box itself, and passing `d` to `v2.std.diagnostic` `diagnostics_merge` failed rustc with E0308 (expected `Option>`, found `Box>`) in the emitted `v2.compiler.infer`. The `.dag` was accepted with zero diagnostics, and only the non-required emit-build lane (`//gunbc/instruments:self-host`) saw it. The author-side repair split the match into two single-level arms, which the rest of the corpus already does by habit. That habit is an unstated workaround: it explains why the population is small and is not evidence that it is zero. The existing trigger of this row covers it: the emitted carrier comes from the declaration, and nested-pattern binders must go through the same unboxing join as single-level arms.", + "OCCURRENCE, 2026-09-28 (warm-wolf-234, precursor to the Bool de-fork): THE ARMS OF A NATIVELY REALIZED COPRODUCT. std.types Bool = True | False is bound to Rust `bool` by gunbc.rust_source_type_bindings, and `match a { True => b False => False }` over it was accepted at zero blocking diagnostics and emitted `Bool::True` / `Bool::False` against a `bool` -- rustc E0308. The type binding said which carrier Bool realizes as and nothing said which of its values each arm is, so the emitter spelled the arm by its SOURCE name, the one spelling the carrier cannot express. It went unexercised because v2.std.logic's structural Bool answered every True/False in the corpus; retiring that declaration exposed it. REPAIRED AT THE OWNING LINK, not at the two sites that tripped it: std.target_representation SourceVariantTargetValue rows keyed on the parent's identity -- a DeclarationRef, or the kernel type name for the kernel mint every module's `Bool` resolves to, admitted by std.types is_kernel_type (the values themselves are target facts in extdeps.languages.rust.representation) -- that identity read once at inference and carried as VariantParentIdentity on VariantPattern and VariantValueBinding, and the emitter spelling the row's value or refusing located (compile_error!) where the identity is not recovered for an arm some row binds -- never falling back to the spelling. Standing controls: fixtures/fixture_closure_rustc/native_bool_variant_probe.dag (rustc, red before, green after), fixtures/fixture_closure_rustc/local_true_false_coproduct_probe.dag (a module-local coproduct whose arms are spelled True/False keeps its own enum, so the rows are identity-keyed), and test.claim.native_variant_realization_witness_test on the emitted bytes.", + "OCCURRENCE, 2026-09-28 (warm-wolf-234, found while choosing the control above; NOT repaired): A MODULE-LOCAL COPRODUCT SPELLED WITH A KERNEL TYPE NAME. `type Bool = True | False` declared in an ordinary module is accepted at zero blocking diagnostics, but kernel names are never overridden in type position, so every signature renders the kernel `bool` while the arms render the local `enum Bool` -- rustc E0308 on the specimen fixtures/fixture_closure_rustc/local_bool_coproduct_probe.dag, measured on origin/main by `gunbc compile --entry` plus cargo check. Two referents for one spelling in one module is the defect; the earlier boundary is the checker, which should refuse a declaration that shadows a kernel name (or the emitter should keep one referent). Rostered here with its specimen so it is not lost; the variant-realization change deliberately does not touch it." ], diff --git a/dag/gunbc/rust_source_type_bindings.dag b/dag/gunbc/rust_source_type_bindings.dag index 80d45ad7bae..0512707d3bb 100644 --- a/dag/gunbc/rust_source_type_bindings.dag +++ b/dag/gunbc/rust_source_type_bindings.dag @@ -2,12 +2,15 @@ module gunbc.rust_source_type_bindings import std.types { List, String, Bool, NonEmptyStr } import std.decl_ref { DeclarationRef, decl_ref } +import std.kernel_type_name { kernel_type_name, KernelTypeNameAdmitted, NotAKernelTypeName } import std.target_representation { - SourceTypeTargetBinding, CheckpointRowMigration, CheckpointRowDisposition, + SourceTypeTargetBinding, SourceVariantTargetValue, VariantParentKey, VariantParentDeclaration, VariantParentKernelType, RepresentationValue, + CheckpointRowMigration, CheckpointRowDisposition, MigratedToExactBinding, ProvenUniqueKernelBinding, StillBareNameDebt } import extdeps.languages.rust.representation { - RustRepresentation, RustStdString, RustI64, RustBool, RustUnit, RustVecU8, RustSerdeJsonValue + RustRepresentation, RustStdString, RustI64, RustBool, RustUnit, RustVecU8, RustSerdeJsonValue, + rust_bool_true_value, rust_bool_false_value } // THE CORPUS'S HALF OF THE THREE-IDENTITY SPLIT (std.target_representation): which of THIS corpus's @@ -63,6 +66,41 @@ data rust_source_type_binding_rows: List +} + +data rust_bool_arm_values: List = [ + BoolArmValue { variant: "True" as NonEmptyStr, value: rust_bool_true_value }, + BoolArmValue { variant: "False" as NonEmptyStr, value: rust_bool_false_value } +] + +fn rust_bool_variant_rows(parent: VariantParentKey) -> List> { + rust_bool_arm_values |> map(a => SourceVariantTargetValue { parent: parent, variant: a.variant, value: a.value }) +} + +fn rust_bool_kernel_variant_rows() -> List> { + match kernel_type_name(name: "Bool") { + KernelTypeNameAdmitted { kernel_name: k } => rust_bool_variant_rows(parent: VariantParentKernelType { kernel_name: k }) + NotAKernelTypeName { name: _ } => [] + } +} + +data rust_source_variant_value_rows: List> = concat( + rust_bool_variant_rows(parent: VariantParentDeclaration { declaration: decl_ref(module_path: "std.types", decl_name: "Bool") }), + rust_bool_kernel_variant_rows() +) + fn rust_bound_declaration_refs() -> List { rust_source_type_binding_rows |> map(r => r.source) } diff --git a/dag/gunbc/stage0/stage0_crate_partition_generated.dag b/dag/gunbc/stage0/stage0_crate_partition_generated.dag index dbfaa480e16..dc78d940300 100644 --- a/dag/gunbc/stage0/stage0_crate_partition_generated.dag +++ b/dag/gunbc/stage0/stage0_crate_partition_generated.dag @@ -73,6 +73,7 @@ data generated_partition_crate_rows: List = [ "extdeps_units_iso_80000_3", "std_occurrence_identity", "std_source_annotation", + "std_kernel_type_name", "std_target_representation", "std_literal_elaboration", "std_operator_realization", diff --git a/dag/std/target_representation.dag b/dag/std/target_representation.dag index beb4e593528..94a2630d5b2 100644 --- a/dag/std/target_representation.dag +++ b/dag/std/target_representation.dag @@ -1,6 +1,7 @@ module std.target_representation import std.types { List, String, Bool, Int, NonEmptyStr } +import std.kernel_type_name { KernelTypeName } import std.decl_ref { DeclarationRef, declaration_ref_eq } // THREE IDENTITIES THAT ONE CHECKPOINT ROW USED TO FUSE, separated because each has a different @@ -124,3 +125,146 @@ fn checkpoint_row_disposition_keeps_bare_row(disposition: CheckpointRowDispositi fn checkpoint_row_migration_for(dag_name: NonEmptyStr, migrations: List) -> CheckpointRowMigration? { migrations |> filter(m => m.dag_name == dag_name) |> first } + +// A NATIVELY REALIZED COPRODUCT HAS ARMS, AND EACH ARM NEEDS A TARGET VALUE. A SourceTypeTargetBinding +// says the declaration std.types Bool realizes as the target's `bool`; it says nothing about which +// of Bool's arms is which of `bool`'s values, so a renderer holding only the type binding spelled +// the arm by its SOURCE name (`Bool::True`) against a carrier that has no such path -- accepted +// source emitting an uncompilable target (gunbc.recurring_failure_mode +// accepted_source_emits_uncompilable_target). The fact is split by owner exactly as the type half is: +// RepresentationValue -- representation -> one of its values, spelled. Owned by the TARGET +// authority and naming no source declaration (Rust's `bool` has the +// two values `true` and `false`). +// SourceVariantTargetValue -- source arm (its parent declaration by identity, the arm by name within +// it) -> one of those values. Owned by the CORPUS, because only the +// corpus knows which of its arms it means by which value. +// Keyed on the parent DeclarationRef, never on the parent's spelling: a module-local coproduct that +// happens to be named Bool with True/False arms has no binding and renders its own enum. +type RepresentationValue { + representation: R + value_spelling: NonEmptyStr +} + +// WHICH COPRODUCT AN ARM BELONGS TO, as one exhaustive key. A reference to a kernel type name +// (std.types kernel_type_set) resolves to the KERNEL MINT, which carries no declaration: the kernel +// namespace is closed, so the mint's name IS its identity -- the same standing +// gunbc.rust_source_type_bindings ProvenUniqueKernelBinding gives the kernel mint at the type level. +// The kernel arm holds std.kernel_type_name KernelTypeName -- the one carrier for "a name +// admitted by std.types is_kernel_type" -- so it is built through kernel_type_name and nowhere else. +type VariantParentKey + = VariantParentDeclaration { declaration: DeclarationRef } + | VariantParentKernelType { kernel_name: KernelTypeName } + +fn variant_parent_key_eq(a: VariantParentKey, b: VariantParentKey) -> Bool { + match a { + VariantParentDeclaration { declaration: da } => + match b { + VariantParentDeclaration { declaration: db } => declaration_ref_eq(a: da, b: db) + VariantParentKernelType { kernel_name: _ } => false + } + VariantParentKernelType { kernel_name: ka } => + match b { + VariantParentDeclaration { declaration: _ } => false + VariantParentKernelType { kernel_name: kb } => ka.name == kb.name + } + } +} + +fn variant_parent_key_label(k: VariantParentKey) -> String { + match k { + VariantParentDeclaration { declaration: d } => concat(d.module_path as String, ".", d.decl_name as String) + VariantParentKernelType { kernel_name: n } => concat("kernel ", n.name) + } +} + +type SourceVariantTargetValue { + parent: VariantParentKey + variant: NonEmptyStr + value: RepresentationValue +} + +// WHICH DECLARATION A VARIANT OCCURRENCE BELONGS TO, read ONCE at inference where the scrutinee's (or +// the value's) resolved type is live, and carried on the typed tree for emission -- the same shape +// std.operator_realization OperandDeclaration carries for a binary operator, for the same measured +// reason: at emission only the module env survives, and re-resolving a spelling there answers by pool +// precedence, not by the reference's own binding. Identified carries the key; Unrecovered is the +// located refusal and says why; BeforeInference is the parser's state for a pattern inference has +// not yet read, and emission treats it as unrecovered. There is no default. +type VariantParentIdentity + = VariantParentIdentified { key: VariantParentKey } + | VariantParentUnrecovered { cause: NonEmptyStr } + | VariantParentBeforeInference + +type VariantValueRealization + = VariantRealizesAsTargetValue { value_spelling: NonEmptyStr } + | VariantRealizesStructurally + | VariantTargetValueUnbound { parent: VariantParentKey, variant: NonEmptyStr } + | VariantTargetValueAmbiguous { parent: VariantParentKey, variant: NonEmptyStr, candidate_count: Int } + | VariantParentIdentityUnavailable { cause: NonEmptyStr } + +fn variant_rows_for(key: VariantParentKey, variant: NonEmptyStr, values: List>) -> List> { + values |> filter(v => variant_parent_key_eq(a: v.parent, b: key) && (v.variant as String) == (variant as String)) +} + +fn variant_value_from_hits(key: VariantParentKey, variant: NonEmptyStr, hits: List>) -> VariantValueRealization { + let n = hits |> count + if n == 1 { + match hits |> first { + Present { value: v } => VariantRealizesAsTargetValue { value_spelling: v.value.value_spelling } + Absent => VariantTargetValueUnbound { parent: key, variant: variant } + } + } else if n == 0 { + VariantTargetValueUnbound { parent: key, variant: variant } + } else { + VariantTargetValueAmbiguous { parent: key, variant: variant, candidate_count: n } + } +} + +// THE DECISION, total over the identity arms. A declared parent with no type binding renders its own +// structure (the ordinary answer); a declared parent bound natively MUST bind every arm it is asked +// about, and a value row whose value belongs to a different representation than the parent is +// bound to cannot answer for it. A kernel parent has no declaration binding to consult: it realizes +// natively exactly where the kernel name has variant rows, and then every arm asked about must have +// one. An arm with no row refuses rather than falling back to the source spelling, because that +// spelling is precisely what the target cannot express. An identity that is not Identified is +// answered as unavailable, never as structural. +fn variant_value_realization( + parent: VariantParentIdentity, + variant: NonEmptyStr, + bindings: List>, + values: List>, + same_representation: fn(R, R) -> Bool +) -> VariantValueRealization { + match parent { + VariantParentBeforeInference => VariantParentIdentityUnavailable { cause: "the variant was never read by inference" as NonEmptyStr } + VariantParentUnrecovered { cause: c } => VariantParentIdentityUnavailable { cause: c } + VariantParentIdentified { key: key } => + match key { + VariantParentKernelType { kernel_name: _ } => + let kernel_rows = values |> filter(v => variant_parent_key_eq(a: v.parent, b: key)) + if kernel_rows |> count == 0 { VariantRealizesStructurally } + else { variant_value_from_hits(key: key, variant: variant, hits: variant_rows_for(key: key, variant: variant, values: values)) } + VariantParentDeclaration { declaration: d } => + match resolve_exact_binding(source: Present { value: d }, rows: bindings) { + ExactBindingAbsent => VariantRealizesStructurally + ExactSourceIdentityUnavailable { cause: c } => VariantParentIdentityUnavailable { cause: c } + ExactBindingAmbiguous { candidate_count: n } => VariantTargetValueAmbiguous { parent: key, variant: variant, candidate_count: n } + ResolvedExactBinding { binding: b } => + variant_value_from_hits(key: key, variant: variant, hits: variant_rows_for(key: key, variant: variant, values: values) |> filter(v => same_representation(v.value.representation, b.representation))) + } + } + } +} + +fn variant_value_realization_refusal_message(r: VariantValueRealization) -> String? { + match r { + VariantRealizesAsTargetValue { value_spelling: _ } => none + VariantRealizesStructurally => none + VariantTargetValueUnbound { parent: p, variant: v } => + Present { value: concat("variant realization: ", variant_parent_key_label(k: p), " realizes natively on this target but its arm `", v as String, "` has no target value row; the source spelling cannot be emitted against the native carrier") } + VariantTargetValueAmbiguous { parent: p, variant: v, candidate_count: n } => + Present { value: concat("variant realization: arm `", v as String, "` of ", variant_parent_key_label(k: p), " has ", to_string(value: n), " target value rows (corpus authoring defect)") } + VariantParentIdentityUnavailable { cause: c } => + Present { value: concat("variant realization: the coproduct this variant belongs to was not recovered (", c as String, "), so whether it realizes natively cannot be decided") } + } +} diff --git a/dag/test/claim/native_variant_realization_witness_test.dag b/dag/test/claim/native_variant_realization_witness_test.dag new file mode 100644 index 00000000000..d06bd40a1f6 --- /dev/null +++ b/dag/test/claim/native_variant_realization_witness_test.dag @@ -0,0 +1,37 @@ +module test.claim.native_variant_realization_witness_test + +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +// THE EMITTED BYTES OF A NATIVELY REALIZED COPRODUCT'S ARMS, through the PRODUCTION v1 emitter +// (compile_dag_rust_emit_check). std.types Bool = True | False realizes as Rust `bool` +// (gunbc.rust_source_type_bindings), and gunbc.rust_source_type_bindings +// rust_source_variant_value_rows binds its arms to that carrier's values, keyed on the declaration. +// The rustc half -- that these bytes type-check -- is fixtures/fixture_closure_rustc/ +// native_bool_variant_probe.dag on the fixture-closure route (v1.compiler.compiler_tests_rust +// ct_native_bool_variant_fixture_closure_discrimination_test). + +// The RED this row turns on: the source spelling `Bool::True` against a `bool`, which is what the +// emitter wrote before the rows existed (rustc E0308). +test fn native_bool_arms_emit_the_carrier_values() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.native_bool_arm_probe\nimport std.types { Bool }\nfn probe(a: Bool, b: Bool) -> Bool {\n match a {\n True => b\n False => False\n }\n}\nfn probe_top() -> Bool { True }\n", + "src/test_claim_native_bool_arm_probe.rs", + ["true => ", "false => false"], + ["Bool::True", "Bool::False"] + ) +} + +// THE IDENTITY CONTROL: a module-local coproduct whose arms are spelled True/False has no row, so it +// keeps its own enum and its arms keep their enum paths. A lowering keyed on the arm spelling would +// pass the row above and fail this one. +test fn local_coproduct_with_true_false_arms_keeps_its_enum() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.local_verdict_arm_probe\ntype Verdict = True | False\nfn probe(a: Verdict) -> Verdict {\n match a {\n True => False\n False => True\n }\n}\n", + "src/test_claim_local_verdict_arm_probe.rs", + ["Verdict::True", "Verdict::False"], + ["true => ", "false => "] + ) +} + diff --git a/fixtures/fixture_closure_rustc/local_bool_coproduct_probe.dag b/fixtures/fixture_closure_rustc/local_bool_coproduct_probe.dag new file mode 100644 index 00000000000..ba5b7dea7e3 --- /dev/null +++ b/fixtures/fixture_closure_rustc/local_bool_coproduct_probe.dag @@ -0,0 +1,20 @@ +module fixture.closure.rustc_local_bool_coproduct_probe + +// A STANDING RED, NOT A CONTROL: a module-local coproduct spelled with a kernel type name. The front +// end ACCEPTS it, but kernel names are never overridden in type position, so every `Bool` in a +// signature renders the kernel `bool` while the arms render the local `enum Bool` -- rustc E0308 +// (gunbc.recurring_failure_mode accepted_source_emits_uncompilable_target, the 2026-09-28 +// kernel-name-shadowing receipt). Either the checker refuses the shadowing declaration or the +// emitter keeps one referent; until then this file is the executable specimen. +type Bool = True | False + +fn local_negate(a: Bool) -> Bool { + match a { + True => False + False => True + } +} + +fn local_top() -> Bool { + True +} diff --git a/fixtures/fixture_closure_rustc/local_true_false_coproduct_probe.dag b/fixtures/fixture_closure_rustc/local_true_false_coproduct_probe.dag new file mode 100644 index 00000000000..bf087e58841 --- /dev/null +++ b/fixtures/fixture_closure_rustc/local_true_false_coproduct_probe.dag @@ -0,0 +1,19 @@ +module fixture.closure.rustc_local_true_false_coproduct_probe + +// THE IDENTITY-KEYED CONTROL for native_bool_variant_probe. This module declares its OWN coproduct +// whose arms are spelled True/False. It has no row in gunbc.rust_source_type_bindings +// rust_source_variant_value_rows, so it renders its own enum and its arms keep their enum paths: a +// lowering keyed on the arm spelling would rewrite them to `true`/`false` against an enum, and rustc +// would refuse. (A local coproduct spelled Bool cannot be this control: see local_bool_coproduct_probe.) +type Verdict = True | False + +fn verdict_negate(a: Verdict) -> Verdict { + match a { + True => False + False => True + } +} + +fn verdict_top() -> Verdict { + True +} diff --git a/fixtures/fixture_closure_rustc/native_bool_variant_probe.dag b/fixtures/fixture_closure_rustc/native_bool_variant_probe.dag new file mode 100644 index 00000000000..98f68e0a259 --- /dev/null +++ b/fixtures/fixture_closure_rustc/native_bool_variant_probe.dag @@ -0,0 +1,31 @@ +module fixture.closure.rustc_native_bool_variant_probe + +import std.types { Bool, Int } + +// THE ARMS OF A NATIVELY REALIZED COPRODUCT, POSED TO RUSTC. std.types Bool = True | False realizes +// as Rust `bool` (gunbc.rust_source_type_bindings), so its arms must be spelled as that carrier's +// two values -- in value position, in pattern position, and nested inside another variant's +// pattern -- by the rows gunbc.rust_source_type_bindings rust_source_variant_value_rows, keyed on the +// declaration. Before that lowering the emitter spelled them `Bool::True` against a `bool`, which +// the front end accepted and rustc refused (gunbc.recurring_failure_mode +// accepted_source_emits_uncompilable_target). +type Gate = Open { admitted: Bool } | Shut + +fn probe_meet(a: Bool, b: Bool) -> Bool { + match a { + True => b + False => False + } +} + +fn probe_top() -> Bool { + True +} + +fn probe_gate_admits(g: Gate) -> Int { + match g { + Open { admitted: True } => 1 + Open { admitted: False } => 2 + Shut => 0 + } +} diff --git a/src/v1/00_core.dag b/src/v1/00_core.dag index 2cf7ce4d18f..550d895536f 100644 --- a/src/v1/00_core.dag +++ b/src/v1/00_core.dag @@ -16,6 +16,7 @@ import std.coercion { import std.dissolution { DissolutionCondition, unbound_dissolution } import std.literal_elaboration { LiteralElaboration } import std.operator_realization { OperandDeclaration } +import std.target_representation { VariantParentIdentity } import std.decl_ref { DeclarationRef } import std.induction { SubValueRelation } import std.occurrence_identity { @@ -142,7 +143,7 @@ fn has_inferred(n: Node) -> Bool { type VarBindingKind = LocalValueBinding | FunctionValueBinding - | VariantValueBinding { parent_enum: String } + | VariantValueBinding { parent_enum: String, parent_identity: VariantParentIdentity } | MatchBoundBinding | ServiceValueBinding @@ -312,7 +313,7 @@ type ExprData type MatchPattern = Bind { declaration: Node } | LitPattern { value: LiteralValue } - | VariantPattern { name: String, parent_enum: String?, field_bindings: List } + | VariantPattern { name: String, parent_enum: String?, field_bindings: List, parent_identity: VariantParentIdentity } | Wildcard // IRREFUTABILITY IS A FACT ABOUT `MatchPattern`, SO IT LIVES WITH THE TYPE. It was previously @@ -327,7 +328,7 @@ fn match_pattern_is_irrefutable(pattern: MatchPattern) -> Bool { match pattern { Wildcard => true Bind { declaration: _ } => true - VariantPattern { name: _, parent_enum: _, field_bindings: _ } => false + VariantPattern { name: _, parent_enum: _, field_bindings: _, parent_identity: _ } => false LitPattern { value: _ } => false } } diff --git a/src/v1/02_parse.dag b/src/v1/02_parse.dag index 72d758a0038..9478790a844 100644 --- a/src/v1/02_parse.dag +++ b/src/v1/02_parse.dag @@ -1,5 +1,6 @@ module v1.compiler.parse +import std.target_representation { VariantParentBeforeInference } import v1.std.core { Unmarked, TestMarked, module_node, import_node, Node, InferredNode, Resolved, CompilerError, TypeVariable, @@ -1320,7 +1321,7 @@ fn occurrence_allocator_after_match_pattern( ) -> OccurrenceIdAllocator { match pattern { Present { value: Bind { declaration: declaration } } => occurrence_allocator_after_node(alloc: alloc, node: declaration) - Present { value: VariantPattern { name: _, parent_enum: _, field_bindings: bindings } } => occurrence_allocator_after_node_list(alloc: alloc, nodes: bindings) + Present { value: VariantPattern { name: _, parent_enum: _, field_bindings: bindings, parent_identity: _ } } => occurrence_allocator_after_node_list(alloc: alloc, nodes: bindings) Present { value: LitPattern { value: _ } } => alloc Present { value: Wildcard } => alloc Absent => alloc @@ -1472,6 +1473,7 @@ fn stamp_parsed_pattern( name: name, parent_enum: parent_enum, field_bindings: field_bindings, + parent_identity: parent_identity, }, } => let stamped = stamp_parsed_node_list( @@ -1486,6 +1488,7 @@ fn stamp_parsed_pattern( name: name, parent_enum: parent_enum, field_bindings: stamped.nodes, + parent_identity: parent_identity, }, }, ctx: stamped.ctx, @@ -6041,7 +6044,7 @@ fn parse_variant_pattern(tokens: TokenStream, ctx: ParseContext, name: String) - if has_err(err: r.err) { return PatternResult { pattern: Wildcard, tokens: r.tokens, ctx: r.ctx, err: r.err } } let r2 = expect(tokens: skip_newlines(tokens: r.tokens), expected: ExpectRBrace) if has_err(err: r2.err) { return PatternResult { pattern: Wildcard, tokens: r2.tokens, ctx: r.ctx, err: r2.err } } - PatternResult { pattern: VariantPattern { name: name, parent_enum: none, field_bindings: r.field_bindings }, tokens: r2.tokens, ctx: r.ctx, err: none } + PatternResult { pattern: VariantPattern { name: name, parent_enum: none, field_bindings: r.field_bindings, parent_identity: VariantParentBeforeInference }, tokens: r2.tokens, ctx: r.ctx, err: none } } else if tok_is_lparen(tok: token_stream_first(stream: tokens)) { let r = parse_pattern(tokens: token_stream_advance(stream: tokens, n: 1), ctx: ctx) if has_err(err: r.err) { return PatternResult { pattern: Wildcard, tokens: r.tokens, ctx: r.ctx, err: r.err } } @@ -6049,9 +6052,9 @@ fn parse_variant_pattern(tokens: TokenStream, ctx: ParseContext, name: String) - if has_err(err: r2.err) { return PatternResult { pattern: Wildcard, tokens: r2.tokens, ctx: r.ctx, err: r2.err } } let minted = mint_parsed_node_identity(ctx: r.ctx) let fb = make_field_binding_node(occurrence_identity: minted.identity, field_name: "0", binding: r.pattern, span: span, name_span: kernel_span(name: "0")) - PatternResult { pattern: VariantPattern { name: name, parent_enum: none, field_bindings: [fb] }, tokens: r2.tokens, ctx: minted.ctx, err: none } + PatternResult { pattern: VariantPattern { name: name, parent_enum: none, field_bindings: [fb], parent_identity: VariantParentBeforeInference }, tokens: r2.tokens, ctx: minted.ctx, err: none } } else { - PatternResult { pattern: VariantPattern { name: name, parent_enum: none, field_bindings: [] }, tokens: tokens, ctx: ctx, err: none } + PatternResult { pattern: VariantPattern { name: name, parent_enum: none, field_bindings: [], parent_identity: VariantParentBeforeInference }, tokens: tokens, ctx: ctx, err: none } } } diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index a4dfd2f20bf..f7795ed3397 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -10,6 +10,8 @@ import std.content_hash { import extdeps.container.oci.digest { oci_other_digest_algorithm, oci_other_digest_encoded } import std.syntax { Add, Sub, Mul, Div, Mod, Eq, Ne, Lt, Gt, Le, Ge, And, Or, NullCoalesce, BinOp, LitStr, LitInt, LitBool, LiteralValue } import std.decl_ref { DeclarationRef, decl_ref, declaration_ref_eq } +import std.target_representation { VariantParentIdentity, VariantParentIdentified, VariantParentUnrecovered, VariantParentDeclaration, VariantParentKernelType } +import std.kernel_type_name { kernel_type_name, KernelTypeNameAdmitted, NotAKernelTypeName } import std.operator_realization { OperandDeclaration } import std.literal_elaboration { LiteralElaboration, LiteralHomomorphism, LiteralUnfolding, PeanoUnfold, BooleanUnfold, UnicodeScalarSequenceUnfold, @@ -24,7 +26,7 @@ import v1.compiler.type_head_exposure { type_declaration_identity_key, type_head_exposure_is_kernel_scalar, type_head_exposure_is_product, type_head_exposure_is_coproduct } -import v1.std.core { Unmarked, +import v1.std.core { Unmarked, declaration_provenance_of, callable_identity, DeclaredCallableIdentity, resolved_node_is_kernel_identity_for_name, Node, InternTable, @@ -740,6 +742,31 @@ fn variant_reference_inferred_node(expected: Node?, name: String, owner_name: St } } +// THE DECLARATION A VARIANT BELONGS TO, read here where the owning coproduct's node is live +// (std.target_representation VariantParentIdentity): the same census-by-identity read +// type_reference_declaration performs for a binary operator's operand, and for the same reason it is +// done at inference and carried -- emission holds only the module env, and re-resolving the owner's +// spelling there answers by pool precedence. An owner the census cannot identify says so; nothing +// here falls back to the owner's spelling or to the reference's file. +fn variant_parent_identity_of(owner: Node?, scope: InferScope) -> VariantParentIdentity { + match owner { + Absent => VariantParentUnrecovered { cause: "no owning coproduct declaration was found for the variant" as NonEmptyStr } + Present { value: o } => + match type_reference_declaration(n: o, source_indices: scope.type_env.source_indices, env: scope.type_env) { + Present { value: od } => VariantParentIdentified { key: VariantParentDeclaration { declaration: od.declaration } } + Absent => + match declaration_provenance_of(item: o) { + KernelMinted { minted_name: m } => + match kernel_type_name(name: m) { + KernelTypeNameAdmitted { kernel_name: k } => VariantParentIdentified { key: VariantParentKernelType { kernel_name: k } } + NotAKernelTypeName { name: _ } => VariantParentUnrecovered { cause: "the owning coproduct is a kernel mint whose name is not a kernel type" as NonEmptyStr } + } + _ => VariantParentUnrecovered { cause: "the owning coproduct is neither an identified corpus declaration nor a kernel type (alias or unresolved)" as NonEmptyStr } + } + } + } +} + // THE EXPECTED COPRODUCT ELECTS A BARE VARIANT SPELLING FIRST (neat-boar-16 ruling, 2026-10-01). A // value-position spelling S checked against a Required expected type whose expansion is a coproduct // declaring an arm S is THAT coproduct's arm: the expected type's declaration decides, over every @@ -756,7 +783,7 @@ fn expected_decided_variant_value(texpr: Node, name: String, decided: Node, expe typed: make_named_expr_node( occurrence_identity: texpr.occurrence_identity, name: name, - expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: decided_name } } }, + expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: decided_name, parent_identity: variant_parent_identity_of(owner: Present { value: decided }, scope: scope) } } }, children: [], inferred: Present { value: Resolved { node: variant_reference_inferred_node(expected: expected, name: name, owner_name: decided_name, scope: scope, fallback: decided) } }, span: texpr.span, @@ -988,7 +1015,7 @@ fn expected_type_is_arrow(expected: Node?) -> Bool { fn infer_var_binding_kind(scope: InferScope, name: String) -> VarBindingKind { match lookup_variant_parent_enum(scope: scope, name: name) { - Present { value: parent_enum } => VariantValueBinding { parent_enum: parent_enum } + Present { value: parent_enum } => VariantValueBinding { parent_enum: parent_enum, parent_identity: variant_parent_identity_of(owner: variant_owner_node(scope: scope, name: name), scope: scope) } Absent => match map_get(scope.locals, name) { Present { value: binding } => @@ -6905,29 +6932,42 @@ fn resolve_pattern_subject(scope: InferScope, scrutinee_subject: PatternSubject) } } +// WHICH PARENT A VARIANT PATTERN WAS READ AGAINST, decided ONCE: the label the emitter spells +// (parent_enum) and the identity the realization rows are keyed on come out of the same branch, so +// the wrapper arms (optional, witness) carry their own unrecovered cause and nothing downstream +// re-derives wrapper-ness by comparing the label as a string (review 72323). +type PatternParentReading { + parent_enum: String? + identity: VariantParentIdentity +} + fn annotate_pattern_parent_enums(pattern: MatchPattern, scrutinee_subject: PatternSubject, site: SourceSpan, scope: InferScope) -> MatchPattern { match pattern { - VariantPattern { name: variant_name, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: variant_name, parent_enum: _, field_bindings: bindings, parent_identity: _ } => let resolved_scrut = resolve_pattern_subject(scope: scope, scrutinee_subject: scrutinee_subject) - let inferred_parent = match resolved_scrut { + let parent_reading = match resolved_scrut { PatternResolved { node: resolved_scrut_node } => let scrutinee_name = authored_name_at(source_indices: scope.type_env.source_indices, node: resolved_scrut_node) let optional_cardinality_subject = resolved_scrut_node.return_cardinality == CardOptional && scrutinee_name != "Optional" let optional_coproduct_subject = scrutinee_name == "Optional" && (variant_name == "Present" || variant_name == "Absent") let witness_container_subject = is_witness_type_name(name: scrutinee_name) && (variant_name == "Holds" || variant_name == "Violates") if (optional_cardinality_subject || optional_coproduct_subject) && (variant_name == "Present" || variant_name == "Absent") { - Present { value: "Optional" } + PatternParentReading { parent_enum: Present { value: "Optional" }, identity: VariantParentUnrecovered { cause: "the arm belongs to the optional wrapper, not to the scrutinee's declared coproduct" as NonEmptyStr } } } else if witness_container_subject { - Present { value: "Witness" } + PatternParentReading { parent_enum: Present { value: "Witness" }, identity: VariantParentUnrecovered { cause: "the arm belongs to the witness wrapper, not to the scrutinee's declared coproduct" as NonEmptyStr } } } else { let is_coproduct = resolved_scrut_node.connective == Disj if is_coproduct { - Present { value: scrutinee_name } - } else { none } + PatternParentReading { parent_enum: Present { value: scrutinee_name }, identity: variant_parent_identity_of(owner: Present { value: resolved_scrut_node }, scope: scope) } + } else { + PatternParentReading { parent_enum: none, identity: VariantParentUnrecovered { cause: "the scrutinee's resolved type is not a coproduct declaration" as NonEmptyStr } } + } } - PatternDynamic { span: _ } => none - PatternLookupBlocked => none + PatternDynamic { span: _ } => PatternParentReading { parent_enum: none, identity: VariantParentUnrecovered { cause: "the scrutinee's type is dynamic" as NonEmptyStr } } + PatternLookupBlocked => PatternParentReading { parent_enum: none, identity: VariantParentUnrecovered { cause: "the scrutinee's type lookup was blocked" as NonEmptyStr } } } + let inferred_parent = parent_reading.parent_enum + let parent_identity = parent_reading.identity let annotated_variant_name = variant_name let variant_lookup = lookup_variant_in_type(scrut: resolved_scrut, variant_name: variant_name, site: site, module_name: scope.module_name, env: scope.type_env, field_binding_count: bindings |> count) let variant_subject = lookup_result_subject(result: variant_lookup) @@ -6941,10 +6981,11 @@ fn annotate_pattern_parent_enums(pattern: MatchPattern, scrutinee_subject: Patte VariantPattern { name: annotated_variant_name, parent_enum: parent_name, - field_bindings: annotated_bindings + field_bindings: annotated_bindings, + parent_identity: parent_identity } Absent => - VariantPattern { name: variant_name, parent_enum: none, field_bindings: annotated_bindings } + VariantPattern { name: variant_name, parent_enum: none, field_bindings: annotated_bindings, parent_identity: parent_identity } } _ => pattern } @@ -6962,7 +7003,7 @@ fn annotate_pattern_parent_enums(pattern: MatchPattern, scrutinee_subject: Patte fn present_arms_over_unresolved_scrutinee(arms: List, span: SourceSpan, module_name: String) -> List { flat_map(arms, arm => match arm_pattern(n: arm) { - VariantPattern { name: n, parent_enum: pe, field_bindings: _ } => + VariantPattern { name: n, parent_enum: pe, field_bindings: _, parent_identity: _ } => if qualified_last_segment(name: n) == "Present" && pe == none { [make_error_node(diagnostic: PresentArmScrutineeTypeUnresolved { pattern: n, span: span }, module_name: module_name)] } else { [] } @@ -7111,7 +7152,7 @@ fn extend_scope_with_pattern_node(scope: InferScope, pattern: MatchPattern, scru Bind { declaration: declaration } => PatternScopeResult { scope: extend_scope_match_bound(scope: scope, name: declaration.name, resolved: pattern_binding_type(subject: scrutinee_subject), provenance: scrutinee_provenance), diagnostics: [] } Wildcard => PatternScopeResult { scope: scope, diagnostics: [] } LitPattern { value: _ } => PatternScopeResult { scope: scope, diagnostics: [] } - VariantPattern { name: vname, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: vname, parent_enum: _, field_bindings: bindings, parent_identity: _ } => let resolved_scrut = resolve_pattern_subject(scope: scope, scrutinee_subject: scrutinee_subject) let variant_lookup = lookup_variant_in_type(scrut: resolved_scrut, variant_name: vname, site: site, module_name: scope.module_name, env: scope.type_env, field_binding_count: bindings |> count) let variant_subject = lookup_result_subject(result: variant_lookup) @@ -7623,15 +7664,15 @@ fn elaborated_expr_node(name: String, expr_data: ExprData, children: List, } } -fn unfold_peano_image(n: Int, zero: String, succ: String, prev_field: String, parent: String, destination_type: Node, span: SourceSpan) -> Node { +fn unfold_peano_image(n: Int, zero: String, succ: String, prev_field: String, parent: String, parent_identity: VariantParentIdentity, destination_type: Node, span: SourceSpan) -> Node { if n <= 0 { elaborated_expr_node( name: zero, - expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: parent } } }, + expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: parent, parent_identity: parent_identity } } }, children: [], destination_type: destination_type, span: span ) } else { - let prev = unfold_peano_image(n: n - 1, zero: zero, succ: succ, prev_field: prev_field, parent: parent, destination_type: destination_type, span: span) + let prev = unfold_peano_image(n: n - 1, zero: zero, succ: succ, prev_field: prev_field, parent: parent, parent_identity: parent_identity, destination_type: destination_type, span: span) let field = make_field_init_node(occurrence_identity: OccurrenceSynthetic, name: prev_field, value: prev, span: span, name_span: elaborated_span(name: prev_field)) elaborated_expr_node( name: succ, @@ -7680,6 +7721,7 @@ fn unfold_literal_image(lit: LiteralValue, elaboration: LiteralElaboration, dest n: n, zero: zero.decl_name as String, succ: succ.decl_name as String, prev_field: prev_field as String, parent: elaboration.destination.decl_name as String, + parent_identity: VariantParentIdentified { key: VariantParentDeclaration { declaration: elaboration.destination } }, destination_type: destination_type, span: span ) _ => make_expr_error_node(occurrence_identity: OccurrenceSynthetic, kind: InternalExprError, message: "literal elaboration: a Peano unfolding row was selected for a non-integer literal (gunbc.structural_realization_bindings keys the row on KernelIntLiteral, so this row is malformed)", span: span) @@ -7689,7 +7731,7 @@ fn unfold_literal_image(lit: LiteralValue, elaboration: LiteralElaboration, dest LitBool { value: b } => elaborated_expr_node( name: if b { t.decl_name as String } else { f.decl_name as String }, - expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: elaboration.destination.decl_name as String } } }, + expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: elaboration.destination.decl_name as String, parent_identity: VariantParentIdentified { key: VariantParentDeclaration { declaration: elaboration.destination } } } } }, children: [], destination_type: destination_type, span: span ) _ => make_expr_error_node(occurrence_identity: OccurrenceSynthetic, kind: InternalExprError, message: "literal elaboration: a Boolean unfolding row was selected for a non-boolean literal (gunbc.structural_realization_bindings keys the row on KernelBoolLiteral, so this row is malformed)", span: span) @@ -7810,7 +7852,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu typed: make_named_expr_node( occurrence_identity: texpr.occurrence_identity, name: name, - expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum } } }, + expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum, parent_identity: variant_parent_identity_of(owner: variant_owner_node(scope: scope, name: name), scope: scope) } } }, children: [], inferred: Present { value: Resolved { node: variant_reference_inferred_node(expected: expected, name: name, owner_name: scope_enum, scope: scope, fallback: binding.resolved) } }, span: span, @@ -7878,7 +7920,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu typed: make_named_expr_node( occurrence_identity: texpr.occurrence_identity, name: name, - expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum } } }, + expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: scope_enum, parent_identity: variant_parent_identity_of(owner: variant_owner_node(scope: scope, name: name), scope: scope) } } }, children: [], inferred: Present { value: Resolved { node: variant_reference_inferred_node(expected: expected, name: name, owner_name: scope_enum, scope: scope, fallback: gbinding.resolved) } }, span: span, @@ -7893,7 +7935,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu typed: make_named_expr_node( occurrence_identity: texpr.occurrence_identity, name: name, - expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: authored_name_at(source_indices: scope.type_env.source_indices, node: exp_enum) } } }, + expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: authored_name_at(source_indices: scope.type_env.source_indices, node: exp_enum), parent_identity: variant_parent_identity_of(owner: Present { value: exp_enum }, scope: scope) } } }, children: [], inferred: Present { value: Resolved { node: exp_enum } }, span: span, @@ -7940,7 +7982,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu typed: make_named_expr_node( occurrence_identity: texpr.occurrence_identity, name: name, - expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: authored_name_at(source_indices: scope.type_env.source_indices, node: exp_enum) } } }, + expr_data: ExprVar { binding_kind: Present { value: VariantValueBinding { parent_enum: authored_name_at(source_indices: scope.type_env.source_indices, node: exp_enum), parent_identity: variant_parent_identity_of(owner: Present { value: exp_enum }, scope: scope) } } }, children: [], inferred: Present { value: Resolved { node: exp_enum } }, span: span, @@ -11581,7 +11623,7 @@ fn provenance_callee_sig(callee: String, param_types: Map, let_p fn descent_pattern_bound_names(pattern: MatchPattern) -> List { match pattern { Bind { declaration: declaration } => [declaration.name] - VariantPattern { name: _, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: _, parent_enum: _, field_bindings: bindings, parent_identity: _ } => bindings |> flat_map(fb => descent_pattern_bound_names(pattern: field_binding_pattern(n: fb))) _ => [] } @@ -11720,7 +11762,7 @@ fn annotate_descent(body: Node, ctx: DescentContext) -> Node { Absent => if scrut_has_inductive { match arm_pattern(n: arm_node) { - VariantPattern { name: vname, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: vname, parent_enum: _, field_bindings: bindings, parent_identity: _ } => match scrut_inducing_field { Present { value: ind_field } => if vname == "Present" { @@ -11737,7 +11779,7 @@ fn annotate_descent(body: Node, ctx: DescentContext) -> Node { per_field_vars: c.per_field_vars, body_locals: c.body_locals } - VariantPattern { name: inner_vname, parent_enum: _, field_bindings: inner_bindings } => + VariantPattern { name: inner_vname, parent_enum: _, field_bindings: inner_bindings, parent_identity: _ } => let inner_ind_fields = inductive_fields_for(env: c.type_env, type_name: ind_field.element_type) inner_bindings |> fold(init: c, f: (ic, inner_fb) => let inner_field_name = field_binding_name_at(n: inner_fb, source_indices: ctx.type_env.source_indices) @@ -12230,7 +12272,7 @@ fn classify_body_provenance(expr: Node, param_names: List, param_types: let arm_provs = arms |> map(arm => let arm_let_prov = match arm_pattern(n: arm) { - VariantPattern { name: vname, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: vname, parent_enum: _, field_bindings: bindings, parent_identity: _ } => fold(bindings, init: let_prov, f: (acc, binding) => let field_label = field_binding_name_at(n: binding, source_indices: type_env.source_indices) let bind_name = match field_binding_pattern(n: binding) { @@ -12529,7 +12571,7 @@ fn intersect_prov_maps(a: Map, b: Map DescentContext? { match arm_pattern(n: arm_node) { - VariantPattern { name: vname, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: vname, parent_enum: _, field_bindings: bindings, parent_identity: _ } => match map_get(sig.variant_provenance, vname) { Present { value: variant_field_map } => let call_args = call_args_by_name(call: scrut, source_indices: ctx.type_env.source_indices) diff --git a/src/v1/04_patterns.dag b/src/v1/04_patterns.dag index 7cc9e948299..2ae7cb8bbab 100644 --- a/src/v1/04_patterns.dag +++ b/src/v1/04_patterns.dag @@ -579,7 +579,7 @@ fn pattern_row_is_irrefutable(row: List) -> Bool { fn pattern_matches_constructor(p: MatchPattern, ctor: String) -> Bool { match p { - VariantPattern { name: n, parent_enum: _, field_bindings: _ } => + VariantPattern { name: n, parent_enum: _, field_bindings: _, parent_identity: _ } => variant_pattern_coverage_key(name: n) == variant_pattern_coverage_key(name: ctor) LitPattern { value: v } => match v { @@ -611,7 +611,7 @@ fn specialize_pattern_row(row: List, ctor: String, fields: List map(f => Wildcard), rest)] } else if pattern_matches_constructor(p: head, ctor: ctor) { match head { - VariantPattern { name: _, parent_enum: _, field_bindings: fbs } => + VariantPattern { name: _, parent_enum: _, field_bindings: fbs, parent_identity: _ } => [concat(fields |> map(f => field_binding_pattern_for(bindings: fbs, field_name: f.name, source_indices: source_indices)), rest)] _ => [concat(fields |> map(f => Wildcard), rest)] } diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index 40e89a0a182..7e51312b340 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -189,7 +189,7 @@ fn emit_simple_expr(expr: Node, target: RenderTarget, source_indices: Map match bk { Present { value: MatchBoundBinding } => false - Present { value: VariantValueBinding { parent_enum: _ } } => false + Present { value: VariantValueBinding { parent_enum: _, parent_identity: _ } } => false _ => true } _ => false @@ -3596,7 +3596,7 @@ fn emit_unified_pattern(pattern: MatchPattern, target: RenderTarget, source_indi match pattern { Bind { declaration: declaration } => emit_ident(name: declaration.name, target: target) LitPattern { value: v } => emit_literal(value: v, target: target) - VariantPattern { name: n, parent_enum: pe, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: pe, field_bindings: fbs, parent_identity: _ } => emit_unified_variant_pattern(name: n, parent_enum: pe, field_bindings: fbs, target: target, source_indices: source_indices) Wildcard => "_" } @@ -3674,7 +3674,7 @@ fn emit_arm_guard(arm: Node, target: RenderTarget, render_guard_expr: fn(Node) - fn emit_go_match_arm_bindings(arm: Node, indent_level: Int, source_indices: Map) -> String { match arm_pattern(n: arm) { - VariantPattern { name: _, parent_enum: _, field_bindings: fbs } => + VariantPattern { name: _, parent_enum: _, field_bindings: fbs, parent_identity: _ } => if fbs |> count == 0 { "" } else { fbs |> map(fb => concat(make_indent(level: indent_level), emit_ident(name: field_binding_name_at(n: fb, source_indices: source_indices), target: Go), " := __gunbcMatch.", emit_export_ident(name: field_binding_name_at(n: fb, source_indices: source_indices), target: Go), "\n")) |> join(separator: "") } diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 196ebd4a099..df74a1e437d 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -2,7 +2,9 @@ module v1.compiler.emit_rust import std.occurrence_identity { OccurrenceSynthetic } import std.decl_ref { decl_ref, DeclarationRef, WholeDeclaration } -import std.target_representation { ResolvedExactBinding, ExactBindingAbsent, ExactBindingAmbiguous, ExactSourceIdentityUnavailable } +import std.target_representation { ResolvedExactBinding, ExactBindingAbsent, ExactBindingAmbiguous, ExactSourceIdentityUnavailable, + VariantParentIdentity, VariantParentUnrecovered, VariantParentBeforeInference, VariantRealizesAsTargetValue, VariantRealizesStructurally, VariantTargetValueUnbound, + VariantTargetValueAmbiguous, VariantParentIdentityUnavailable, variant_value_realization_refusal_message } import extdeps.languages.rust.representation { rust_exact_type_checkpoint } import std.repair_input_origin { repair_input_origin_candidates, @@ -148,7 +150,8 @@ import v1.compiler.coercion { coerce_primitive_type, is_copy, target_callable, rust_lookup_exact_binding, declaration_realizes_natively_on_rust, type_reference_realization, declaration_realization, type_realization_decision, realized_checkpoint, realization_host_numeric_spelling, - realization_is_host_numeric, provenance_declares_structurally + realization_is_host_numeric, provenance_declares_structurally, + rust_variant_value_realization, rust_variant_arm_is_bound_somewhere } import std.coercion { TypeDeclarationProvenance, CorpusDeclared, KernelMinted, DeclarationIdentityAbsent, @@ -4315,7 +4318,7 @@ fn collect_items_field_import_surface_names(surface_names: List, emit_in // 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 { match pattern { - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + 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) { Present { value: parent } => if parent == "" { [] } else { [parent] } Absent => [] @@ -4404,7 +4407,7 @@ fn emit_scrutinee_type_name(scrutinee: Node, source_indices: Map) -> List { match pattern { - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: _ } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: _, parent_identity: _ } => let bare_n = qualified_last_segment(name: n) match pattern_parent_enum(name: bare_n, parent_enum: parent_enum, scrut_type: scrut_type, type_summaries: type_summaries) { Present { value: parent } => if parent != "" { [parent] } else { [] } @@ -4416,7 +4419,7 @@ fn collect_pattern_rc_prelude_parent_enums(pattern: MatchPattern, scrut_type: St fn collect_rc_pattern_prelude_parent_enums(pattern: MatchPattern, rc_analysis: RcPatternAnalysis, scrut_type: String, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> List { match pattern { - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: _ } => let bare_n = qualified_last_segment(name: n) if is_optional_variant_name(name: bare_n) && is_optional_parent(parent_enum: parent_enum) { if fbs |> count == 1 { @@ -9778,7 +9781,7 @@ fn collect_field_binding_string_guards(field_bindings: List, path_prefix: fn collect_pattern_string_guards(pattern: MatchPattern, path_prefix: List, source_indices: Map) -> String { match pattern { - VariantPattern { name: n, parent_enum: parent, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent, field_bindings: fbs, parent_identity: _ } => if n == "Present" && parent == Present { value: "Optional" } && fbs |> count == 1 { match fbs |> first { Present { value: fb } => @@ -9845,8 +9848,12 @@ fn emit_pattern(pattern: MatchPattern, path_prefix: List, shared_types: match pattern { Bind { declaration: declaration } => emit_ident(name: declaration.name, target: Rust) LitPattern { value: v } => rust_literal_for_pattern(value: v) - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: identity } => + match rust_native_variant_spelling(parent: identity, leaf_name: qualified_last_segment(name: n)) { + Present { value: native } => native + Absent => emit_variant_pattern(name: n, parent_enum: parent_enum, field_bindings: fbs, path_prefix: path_prefix, shared_types: shared_types, scrut_type: scrut_type, source_indices: source_indices, emit_info: emit_info) + } Wildcard => "_" } } @@ -10160,7 +10167,7 @@ fn field_needs_rc_ref(field_name: String, rc_analysis: RcPatternAnalysis) -> Boo // `AdmitExportsFold`, four record sites). The record is decided by the same shared set. fn analyze_rc_pattern(pattern: MatchPattern, scrut_type: String, shared_types: Set, emit_info: EmitGraphInfo, source_indices: Map) -> RcPatternAnalysis { match pattern { - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: _ } => let bare_n = qualified_last_segment(name: n) if is_optional_variant_name(name: bare_n) && is_optional_parent(parent_enum: parent_enum) { if fbs |> count == 1 { @@ -10208,7 +10215,7 @@ fn analyze_rc_pattern(pattern: MatchPattern, scrut_type: String, shared_types: S fn box_bound_fields_for_pattern(pattern: MatchPattern, shared_types: Set, emit_info: EmitGraphInfo, scope: InferScope) -> List { match pattern { - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: _ } => let bare_n = qualified_last_segment(name: n) if is_optional_variant_name(name: bare_n) && is_optional_parent(parent_enum: parent_enum) { [] @@ -10281,8 +10288,12 @@ fn emit_pattern_rc_aware(pattern: MatchPattern, path_prefix: List, rc_an match pattern { Bind { declaration: declaration } => emit_ident(name: declaration.name, target: Rust) LitPattern { value: v } => rust_literal_for_pattern(value: v) - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: identity } => + match rust_native_variant_spelling(parent: identity, leaf_name: qualified_last_segment(name: n)) { + Present { value: native } => native + Absent => emit_variant_pattern_rc_aware(name: n, parent_enum: parent_enum, field_bindings: fbs, path_prefix: path_prefix, rc_analysis: rc_analysis, shared_types: shared_types, scrut_type: scrut_type, source_indices: source_indices, emit_info: emit_info) + } Wildcard => "_" } } @@ -10417,7 +10428,7 @@ fn resolved_variant_pattern_shape_for(name: String, parent_enum: String?, scrut_ fn collect_pattern_rc_variant_guards(pattern: MatchPattern, rc_analysis: RcPatternAnalysis, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { match pattern { - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: _ } => let bare_n = qualified_last_segment(name: n) if is_optional_variant_name(name: bare_n) && is_optional_parent(parent_enum: parent_enum) { if fbs |> count == 1 { @@ -10444,7 +10455,7 @@ fn collect_pattern_rc_variant_guards(pattern: MatchPattern, rc_analysis: RcPatte if match_pattern_is_irrefutable(pattern: fb_pat) { [] } else { match fb_pat { - VariantPattern { name: inner_n, parent_enum: inner_parent, field_bindings: _ } => + VariantPattern { name: inner_n, parent_enum: inner_parent, field_bindings: _, parent_identity: _ } => let inner_analysis = analyze_rc_pattern(pattern: fb_pat, scrut_type: "", shared_types: shared_types, emit_info: emit_info, source_indices: source_indices) let inner_guard = collect_pattern_rc_variant_guards(pattern: fb_pat, rc_analysis: inner_analysis, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) if inner_guard == "" { @@ -10476,7 +10487,7 @@ fn rust_as_ref_let_is_irrefutable(pattern: MatchPattern, emit_info: EmitGraphInf if match_pattern_is_irrefutable(pattern: pattern) { true } else { match pattern { - VariantPattern { name: n, parent_enum: parent, field_bindings: _ } => + VariantPattern { name: n, parent_enum: parent, field_bindings: _, parent_identity: _ } => 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 } => @@ -10493,7 +10504,7 @@ fn rust_as_ref_let_is_irrefutable(pattern: MatchPattern, emit_info: EmitGraphInf fn rc_pattern_preludes(pattern: MatchPattern, rc_analysis: RcPatternAnalysis, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { match pattern { - VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: parent_enum, field_bindings: fbs, parent_identity: _ } => let bare_n = qualified_last_segment(name: n) if is_optional_variant_name(name: bare_n) && is_optional_parent(parent_enum: parent_enum) { if fbs |> count == 1 { @@ -10576,9 +10587,57 @@ fn explicit_record_struct_name(type_name: String?, inferred_node: Node, shared_t fn is_simple_type_node(n: Node, source_indices: Map) -> Bool { is_rust_value_type(n: n, source_indices: source_indices) } +// A VARIANT OF A NATIVELY REALIZED COPRODUCT IS SPELLED AS THE TARGET VALUE ITS ROW NAMES, in value +// and in pattern position alike (std.types Bool's True/False over Rust `bool` are `true`/`false`). +// Present answers the whole spelling for the occurrence -- the target value, or a located +// compile_error! refusal; Absent means the occurrence renders its own enum path as before. The +// decision is v1.compiler.coercion rust_variant_value_realization over the identity inference +// carried; see rust_variant_arm_is_bound_somewhere for why an unidentified occurrence refuses only +// when its arm is one a row binds. +fn rust_native_variant_spelling(parent: VariantParentIdentity, leaf_name: String) -> String? { + match parent { + VariantParentBeforeInference => + Present { value: emit_rust_compile_error_expr(message: concat("variant realization: `", leaf_name, "` reached emission without inference having read which coproduct it belongs to (VariantParentBeforeInference); an unread occurrence is refused rather than rendered as either the native value or its enum path")) } + _ => rust_native_variant_spelling_of_read(parent: parent, leaf_name: leaf_name) + } +} + +// An occurrence inference has read: Identified, or Unrecovered with its cause. +fn rust_native_variant_spelling_of_read(parent: VariantParentIdentity, leaf_name: String) -> String? { + let r = rust_variant_value_realization(parent: parent, variant: leaf_name) + match r { + VariantRealizesAsTargetValue { value_spelling: s } => Present { value: s as String } + VariantRealizesStructurally => none + VariantParentIdentityUnavailable { cause: _ } => + if rust_variant_arm_is_bound_somewhere(variant: leaf_name) { + match variant_value_realization_refusal_message(r: r) { + Present { value: m } => Present { value: emit_rust_compile_error_expr(message: m) } + Absent => none + } + } else { none } + VariantTargetValueUnbound { parent: _, variant: _ } => + match variant_value_realization_refusal_message(r: r) { + Present { value: m } => Present { value: emit_rust_compile_error_expr(message: m) } + Absent => none + } + VariantTargetValueAmbiguous { parent: _, variant: _, candidate_count: _ } => + match variant_value_realization_refusal_message(r: r) { + Present { value: m } => Present { value: emit_rust_compile_error_expr(message: m) } + Absent => none + } + } +} + +fn rust_native_variant_spelling_of_binding(binding_kind: VarBindingKind?, leaf_name: String) -> String? { + match binding_kind { + Present { value: VariantValueBinding { parent_enum: _, parent_identity: identity } } => rust_native_variant_spelling(parent: identity, leaf_name: leaf_name) + _ => none + } +} + fn variant_parent_from_binding_kind(binding_kind: VarBindingKind?) -> String? { match binding_kind { - Present { value: VariantValueBinding { parent_enum: parent_enum } } => Present { value: parent_enum } + Present { value: VariantValueBinding { parent_enum: parent_enum, parent_identity: _ } } => Present { value: parent_enum } _ => none } } @@ -10736,6 +10795,12 @@ fn emit_var_ref(name: String, binding_kind: VarBindingKind?, resolved_type: Infe let variant_parent = effective_variant_parent(name: resolved_name, binding_kind: binding_kind, resolved_type: resolved_type, emit_info: emit_info, source_indices: source_indices) if (leaf_name == "none" || leaf_name == "None") && variant_parent == none { emit_none_keyword_for_resolved_type(resolved_type: resolved_type) } else if leaf_name == "true" || leaf_name == "false" { emit_keyword(key: leaf_name, target: Rust) } + else if rust_native_variant_spelling_of_binding(binding_kind: binding_kind, leaf_name: leaf_name) != none { + match rust_native_variant_spelling_of_binding(binding_kind: binding_kind, leaf_name: leaf_name) { + Present { value: s } => s + Absent => "" + } + } else { let moves_by_value = set_contains(emit_info.movable, resolved_name) @@ -10801,6 +10866,9 @@ fn emit_typed_expr_base(texpr: Node, registry: Map, scope: Inf if (leaf_name == "none" || leaf_name == "None") && variant_parent == none { emit_none_keyword_for_resolved_type(resolved_type: texpr.inferred) } else if leaf_name == "true" || leaf_name == "false" { emit_keyword(key: leaf_name, target: Rust) } else { + match rust_native_variant_spelling_of_binding(binding_kind: binding_kind, leaf_name: leaf_name) { + Present { value: native } => native + Absent => match variant_parent { Present { value: enum_name } => if freemonoid_empty_from_variant_parent(leaf_name: leaf_name, enum_name: enum_name) { @@ -10832,6 +10900,7 @@ fn emit_typed_expr_base(texpr: Node, registry: Map, scope: Inf emit_value_ref_ident(name: resolved_name, self_module: scope.module_name, registry: registry, emit_info: emit_info) } } + } } _ => emit_typed_expr(texpr: texpr, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024) } @@ -13111,14 +13180,14 @@ fn emit_typed_first_arg(args: List, registry: Map, scope fn freemonoid_match_arm_for(arms: List, variant: String) -> Node? { arms |> filter(arm => match arm_pattern(n: arm) { - VariantPattern { name: n, parent_enum: _, field_bindings: _ } => qualified_last_segment(name: n) == variant + VariantPattern { name: n, parent_enum: _, field_bindings: _, parent_identity: _ } => qualified_last_segment(name: n) == variant _ => false }) |> first } fn arm_resolved_parent_enum(arm: Node, scrut_type: String, type_summaries: Map) -> String? { match arm_pattern(n: arm) { - VariantPattern { name: n, parent_enum: pe, field_bindings: _ } => + 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) _ => none } @@ -13273,7 +13342,7 @@ fn fm_head_bind_name(p: MatchPattern) -> String? { Wildcard => Present { value: "_" } Bind { declaration: d } => Present { value: d.name } LitPattern { value: _ } => none - VariantPattern { name: _, parent_enum: _, field_bindings: _ } => none + VariantPattern { name: _, parent_enum: _, field_bindings: _, parent_identity: _ } => none } } @@ -13293,7 +13362,7 @@ fn fm_analyze_pattern(pattern: MatchPattern, si: Map, fuel Wildcard => FmSpine { exact: false, len: 0, head_binds: [], tail_bind: "_" } Bind { declaration: d } => FmSpine { exact: false, len: 0, head_binds: [], tail_bind: d.name } LitPattern { value: _ } => FmUnsupportedArm { cause: FmLiteralAgainstList } - VariantPattern { name: n, parent_enum: _, field_bindings: fbs } => + VariantPattern { name: n, parent_enum: _, field_bindings: fbs, parent_identity: _ } => let bare = qualified_last_segment(name: n) if bare == "Empty" { FmSpine { exact: true, len: 0, head_binds: [], tail_bind: "" } @@ -13570,7 +13639,7 @@ fn ungroupable_arm_plan(variant: String, pat_str: String) -> RcGroupedArmPlan { fn rc_arm_plain_bindings(pattern: MatchPattern, ref_field: String, source_indices: Map) -> List { match pattern { - VariantPattern { name: _, parent_enum: _, field_bindings: fbs } => + VariantPattern { name: _, parent_enum: _, field_bindings: fbs, parent_identity: _ } => fbs |> flat_map(fb => let fb_name = field_binding_name_at(n: fb, source_indices: source_indices) if fb_name == ref_field { [] } @@ -13587,7 +13656,7 @@ fn rc_arm_plain_bindings(pattern: MatchPattern, ref_field: String, source_indice fn rc_arm_has_refutable_plain_field(pattern: MatchPattern, ref_field: String, source_indices: Map) -> Bool { match pattern { - VariantPattern { name: _, parent_enum: _, field_bindings: fbs } => + VariantPattern { name: _, parent_enum: _, field_bindings: fbs, parent_identity: _ } => fbs |> any(fb => field_binding_name_at(n: fb, source_indices: source_indices) != ref_field && !match_pattern_is_irrefutable(pattern: field_binding_pattern(n: fb)) @@ -13633,7 +13702,7 @@ fn rc_group_representative(entries: List, variant: String) -> fn variant_pattern_field_binding_named(pattern: MatchPattern, field_name: String, source_indices: Map) -> Node? { match pattern { - VariantPattern { name: _, parent_enum: _, field_bindings: fbs } => + VariantPattern { name: _, parent_enum: _, field_bindings: fbs, parent_identity: _ } => fbs |> filter(fb => field_binding_name_at(n: fb, source_indices: source_indices) == field_name) |> first _ => none } @@ -13641,7 +13710,7 @@ fn variant_pattern_field_binding_named(pattern: MatchPattern, field_name: String fn variant_pattern_bare_name(pattern: MatchPattern) -> String { match pattern { - VariantPattern { name: n, parent_enum: _, field_bindings: _ } => qualified_last_segment(name: n) + VariantPattern { name: n, parent_enum: _, field_bindings: _, parent_identity: _ } => qualified_last_segment(name: n) _ => "" } } diff --git a/src/v1/coercion.dag b/src/v1/coercion.dag index 7b6f864042f..26ee2315343 100644 --- a/src/v1/coercion.dag +++ b/src/v1/coercion.dag @@ -17,12 +17,13 @@ import std.decl_ref { DeclarationRef } import std.target_representation { ExactBindingResolution, ResolvedExactBinding, ExactBindingAbsent, ExactBindingAmbiguous, ExactSourceIdentityUnavailable, - resolve_exact_binding, checkpoint_row_migration_for, checkpoint_row_disposition_keeps_bare_row + resolve_exact_binding, checkpoint_row_migration_for, checkpoint_row_disposition_keeps_bare_row, + VariantParentIdentity, VariantValueRealization, variant_value_realization } -import extdeps.languages.rust.representation { RustRepresentation, rust_exact_type_checkpoint } +import extdeps.languages.rust.representation { RustRepresentation, rust_exact_type_checkpoint, rust_representation_eq } -import gunbc.rust_source_type_bindings { rust_source_type_binding_rows, checkpoint_row_migration_rows } +import gunbc.rust_source_type_bindings { rust_source_type_binding_rows, checkpoint_row_migration_rows, rust_source_variant_value_rows } import std.types { container_template_algebra, canonical_container_names, NonEmptyStr } @@ -683,3 +684,27 @@ fn extract_coercion_tests() -> List { copy_tests(), template_application_tests()) } + +// WHAT A VARIANT OCCURRENCE REALIZES AS ON RUST, decided from the declaration-keyed rows +// (gunbc.rust_source_type_bindings rust_source_type_binding_rows and rust_source_variant_value_rows) +// and the identity inference carried on the occurrence -- never from the parent's spelling. Target +// generic in std.target_representation variant_value_realization; this is the Rust binding of it. +fn rust_variant_value_realization(parent: VariantParentIdentity, variant: String) -> VariantValueRealization { + variant_value_realization( + parent: parent, + variant: variant as NonEmptyStr, + bindings: rust_source_type_binding_rows, + values: rust_source_variant_value_rows, + same_representation: fn(a, b) { rust_representation_eq(a: a, b: b) } + ) +} + +// WHETHER AN UNIDENTIFIED VARIANT OCCURRENCE COULD HAVE NEEDED A TARGET VALUE: its arm is spelled +// like an arm some row binds. This never SELECTS a realization -- a spelling cannot, which is the +// whole reason the rows are identity-keyed -- it only decides that an occurrence whose identity was +// not recovered cannot be shown to render structurally, so it must refuse rather than emit the +// source spelling (the absorbing fallback DESIGN section 5 forbids). An unidentified occurrence +// whose arm no row mentions cannot be a native arm and keeps its structural rendering. +fn rust_variant_arm_is_bound_somewhere(variant: String) -> Bool { + rust_source_variant_value_rows |> any(v => (v.variant as String) == variant) +} diff --git a/src/v1/compile.dag b/src/v1/compile.dag index 5199fa4c27c..7687d7a8055 100644 --- a/src/v1/compile.dag +++ b/src/v1/compile.dag @@ -403,7 +403,7 @@ fn function_value_target(texpr: Node, visible: Map, source_indic match kind { FunctionValueBinding => visible_or_qualified_key(visible: visible, name: authored_name_at(source_indices: source_indices, node: texpr)) LocalValueBinding => none - VariantValueBinding { parent_enum: _ } => none + VariantValueBinding { parent_enum: _, parent_identity: _ } => none MatchBoundBinding => none ServiceValueBinding => none } @@ -807,7 +807,7 @@ fn var_binding_kind_name(value: VarBindingKind) -> String { match value { LocalValueBinding => "LocalValueBinding" FunctionValueBinding => "FunctionValueBinding" - VariantValueBinding { parent_enum: _ } => "VariantValueBinding" + VariantValueBinding { parent_enum: _, parent_identity: _ } => "VariantValueBinding" MatchBoundBinding => "MatchBoundBinding" ServiceValueBinding => "ServiceValueBinding" } @@ -915,7 +915,7 @@ fn serialize_match_pattern(pattern: MatchPattern, source_indices: Map concat("{\"kind\": \"LitPattern\", \"value\": ", serialize_literal(value: inner), "}") - VariantPattern { name: inner, parent_enum: parent_enum, field_bindings: field_bindings } => + VariantPattern { name: inner, parent_enum: parent_enum, field_bindings: field_bindings, parent_identity: _ } => concat( "{\"kind\": \"VariantPattern\", \"name\": ", json_quote(s: inner), ", \"parent_enum\": ", json_optional_string(value: parent_enum), @@ -1100,7 +1100,7 @@ fn serialize_expr_data(expr_node: Node, source_indices: Map concat("{\"kind\": ", json_quote(s: var_binding_kind_name(value: inner)), match inner { - VariantValueBinding { parent_enum: parent_enum } => + VariantValueBinding { parent_enum: parent_enum, parent_identity: _ } => concat(", \"parent_enum\": ", json_quote(s: parent_enum)) _ => "" }, diff --git a/src/v1/compiler_tests_rust.dag b/src/v1/compiler_tests_rust.dag index fca86509012..b4e6f89d85c 100644 --- a/src/v1/compiler_tests_rust.dag +++ b/src/v1/compiler_tests_rust.dag @@ -558,6 +558,52 @@ fn ct_nested_refinement_cast_fixture_closure_discrimination_test() -> String { " }\n\n") } +fn ct_native_bool_variant_fixture_closure_discrimination_test() -> String { + concat( + " /// THE ARMS OF A NATIVELY REALIZED COPRODUCT, JUDGED BY RUSTC, AND THE IDENTITY CONTROL BESIDE IT.\n", + " ///\n", + " /// The subject is `v1.compiler.emit_rust` `rust_native_variant_spelling`: an arm of a\n", + " /// coproduct that realizes natively (std.types Bool over Rust `bool`) is spelled as the\n", + " /// carrier value its declaration-keyed row names, in value, pattern and nested-pattern\n", + " /// position. The first pair's control is that fixture and must COMPILE; before the rows it\n", + " /// emitted `Bool::True` against a `bool` and rustc refused it. The second pair's control is a\n", + " /// module-local coproduct whose arms are spelled True/False, which has no row and must keep its own enum -- the\n", + " /// evidence that the rows are keyed on identity rather than on the spelling. Both reds are\n", + " /// the route's own adjudicated red.\n", + " ///\n", + " /// #[ignore] AND WHY, on the same terms as the pairs beside it: each pair spawns cargo and\n", + " /// compiles two emitted crates. It is RUNNABLE ON DEMAND -- `cargo test --release -p\n", + " /// v1-compiler --lib native_bool_variant_fixture_closure_discrimination -- --ignored`. No CI\n", + " /// path invokes it (gunbc.rung_drop rust_unit_tests_off_the_merge_path); the emitted-bytes\n", + " /// half that does run on the floor is test.claim.native_variant_realization_witness_test.\n", + " #[test]\n", + " #[ignore]\n", + " fn native_bool_variant_fixture_closure_discrimination() {\n", + " let probe_root = crate::cli_run::local_emit_compile_probe_root().unwrap();\n", + " for (label, pair) in [\n", + " (\"native-bool-variant\", crate::cli_run::run_native_bool_variant_discrimination(&probe_root)),\n", + " (\"local-true-false-coproduct\", crate::cli_run::run_local_true_false_coproduct_discrimination(&probe_root)),\n", + " ] {\n", + " for line in crate::cli_run::fixture_discrimination_report(&pair) {\n", + " eprintln!(\"{} {}\", label, line);\n", + " }\n", + " assert!(\n", + " crate::cli_run::fixture_closure_reached_rustc(&pair.red),\n", + " \"{}: the red arm never reached a rustc verdict: {}\",\n", + " label,\n", + " crate::cli_run::fixture_closure_summary(&pair.red)\n", + " );\n", + " assert!(\n", + " crate::cli_run::fixture_discrimination_passed(&pair),\n", + " \"{}: the control must COMPILE and the route red must still be refused by rustc in its own module; control={} red={}\",\n", + " label,\n", + " crate::cli_run::fixture_closure_summary(&pair.green),\n", + " crate::cli_run::fixture_closure_summary(&pair.red)\n", + " );\n", + " }\n", + " }\n\n") +} + fn ct_phantom_marker_identity_fixture_closure_discrimination_test() -> String { concat( " /// THE PHANTOM-MARKER POSITION PAIR, JUDGED BY RUSTC, THROUGH THE FIXTURE-CLOSURE ROUTE.\n", @@ -5353,6 +5399,7 @@ fn compiler_tests_source() -> String { ct_evaluation_budget_consequence_falsifier_test(), ct_function_value_adapter_fixture_closure_discrimination_test(), ct_nested_refinement_cast_fixture_closure_discrimination_test(), + ct_native_bool_variant_fixture_closure_discrimination_test(), ct_phantom_marker_identity_fixture_closure_discrimination_test(), ct_empty_map_turbofish_fixture_closure_discrimination_test(), ct_argv_word_list_splice_fixture_closure_discrimination_test(), diff --git a/src/v1/complexity.dag b/src/v1/complexity.dag index 0588e869099..579a8d93b46 100644 --- a/src/v1/complexity.dag +++ b/src/v1/complexity.dag @@ -1737,7 +1737,7 @@ fn expr_contains_descent(expr: Node, param_name: String, vars: Map fn collect_field_binding_names(fb: Node, vars: Map) -> Map { match field_binding_pattern(n: fb) { Bind { declaration: declaration } => map_insert(vars, declaration.name, true) - VariantPattern { name: _, parent_enum: _, field_bindings: nested } => + VariantPattern { name: _, parent_enum: _, field_bindings: nested, parent_identity: _ } => nested |> fold(init: vars, f: (inner, nested_fb) => collect_field_binding_names(fb: nested_fb, vars: inner) ) @@ -1772,7 +1772,7 @@ fn is_match_option_descent(val: Node, param_name: String, vars: Map any(arm_node => match arm_pattern(n: arm_node) { - VariantPattern { name: _, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: _, parent_enum: _, field_bindings: bindings, parent_identity: _ } => let binding_names = bindings |> fold(init: empty_map(), f: (acc, fb) => collect_field_binding_names(fb: fb, vars: acc) ) @@ -1889,7 +1889,7 @@ fn collect_descent_vars(body: Node, param_name: String, vars: Map, let with_patterns = if scrut_is_descent || scrut_is_param { match_arm_nodes(texpr: body) |> fold(init: vars, f: (acc, arm_node) => match arm_pattern(n: arm_node) { - VariantPattern { name: _, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: _, parent_enum: _, field_bindings: bindings, parent_identity: _ } => bindings |> fold(init: acc, f: (inner, fb) => collect_field_binding_names(fb: fb, vars: inner) ) @@ -1980,7 +1980,7 @@ fn all_self_calls_descend_inc(body: Node, func_name: String, param_name: String, let arms_ok = match_arm_nodes(texpr: body) |> all(arm_node => let arm_vars = if scrut_is_descent || scrut_is_param { match arm_pattern(n: arm_node) { - VariantPattern { name: _, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: _, parent_enum: _, field_bindings: bindings, parent_identity: _ } => bindings |> fold(init: vars, f: (inner, fb) => collect_field_binding_names(fb: fb, vars: inner) ) @@ -2300,7 +2300,7 @@ fn collect_evidence_incremental(body: Node, func_name: String, param_name: Strin else { let arm_vars = if scrut_is_descent || scrut_is_param { match arm_pattern(n: arm_node) { - VariantPattern { name: _, parent_enum: _, field_bindings: bindings } => + VariantPattern { name: _, parent_enum: _, field_bindings: bindings, parent_identity: _ } => bindings |> fold(init: vars, f: (inner, fb) => collect_field_binding_names(fb: fb, vars: inner) ) diff --git a/src/v1/dag_collect.dag b/src/v1/dag_collect.dag index bf584386b4b..03e6b70f2da 100644 --- a/src/v1/dag_collect.dag +++ b/src/v1/dag_collect.dag @@ -97,7 +97,7 @@ fn dag_collect_inferred(value: InferredNode?, slots: Map fn dag_collect_match_pattern(pattern: MatchPattern?, slots: Map, collision_errors: List) -> Map { match pattern { Present { value: Bind { declaration: d } } => dag_collect_insert_slots(node: d, slots: slots, collision_errors: collision_errors) - Present { value: VariantPattern { name: _, parent_enum: _, field_bindings: fbs } } => + Present { value: VariantPattern { name: _, parent_enum: _, field_bindings: fbs, parent_identity: _ } } => dag_collect_nodes_list(nodes: fbs, slots: slots, collision_errors: collision_errors) Present { value: LitPattern { value: _ } } => slots Present { value: Wildcard } => slots diff --git a/src/v1/dag_collect_support.dag b/src/v1/dag_collect_support.dag index 4c60e7bf4bf..2162ca208a3 100644 --- a/src/v1/dag_collect_support.dag +++ b/src/v1/dag_collect_support.dag @@ -137,7 +137,7 @@ fn match_pattern_fingerprint_rec(pattern: MatchPattern?) -> String { hash_combine(atom_identity_hash("Bind"), dag_node_surface_fingerprint_rec(node: d)) Present { value: LitPattern { value: v } } => atom_identity_hash(concat("LitPattern:", literal_value_fingerprint(value: v))) - Present { value: VariantPattern { name: n, parent_enum: pe, field_bindings: fbs } } => + Present { value: VariantPattern { name: n, parent_enum: pe, field_bindings: fbs, parent_identity: _ } } => let base = atom_identity_hash(concat( "VariantPattern:", n, "|", match pe { Present { value: p } => p Absent => "" })) diff --git a/src/v1/stage0/src/bin/infer_semantics_witness.rs b/src/v1/stage0/src/bin/infer_semantics_witness.rs index 606d9fd4019..832692293ea 100644 --- a/src/v1/stage0/src/bin/infer_semantics_witness.rs +++ b/src/v1/stage0/src/bin/infer_semantics_witness.rs @@ -413,6 +413,9 @@ fn variant_arm(name: &str) -> Rc { name: name.to_string(), parent_enum: None, field_bindings: Rc::new(vec![]), + parent_identity: Rc::new( + v1_compiler::std_target_representation::VariantParentIdentity::VariantParentBeforeInference, + ), }), None, unit_expr(), @@ -932,6 +935,9 @@ fn optional_present_absent_patterns_keep_canonical_names() { name: "Present".to_string(), parent_enum: None, field_bindings: Rc::new(vec![]), + parent_identity: Rc::new( + v1_compiler::std_target_representation::VariantParentIdentity::VariantParentBeforeInference, + ), }), subject.clone(), zero_span(), @@ -942,6 +948,9 @@ fn optional_present_absent_patterns_keep_canonical_names() { name: "Absent".to_string(), parent_enum: None, field_bindings: Rc::new(vec![]), + parent_identity: Rc::new( + v1_compiler::std_target_representation::VariantParentIdentity::VariantParentBeforeInference, + ), }), subject, zero_span(), @@ -1090,6 +1099,9 @@ fn real_optional_coproduct_preserves_present_absent_pattern_names() { name: "Present".to_string(), parent_enum: None, field_bindings: Rc::new(vec![]), + parent_identity: Rc::new( + v1_compiler::std_target_representation::VariantParentIdentity::VariantParentBeforeInference, + ), }), subject, zero_span(), diff --git a/src/v1/stage0/src/cli_run.rs b/src/v1/stage0/src/cli_run.rs index de7a0a1f4a8..d979d1f5c54 100644 --- a/src/v1/stage0/src/cli_run.rs +++ b/src/v1/stage0/src/cli_run.rs @@ -11558,6 +11558,7 @@ pub enum WitnessRuntimeCause { TypeError, CrossRepresentationEquality, StringRealizationStraddle, + VariantRealizationRefused, PoolRootContributesNothing, PatternMatchFailure, /// A REST response value did not inhabit its declared coproduct (see @@ -11596,6 +11597,7 @@ impl WitnessRuntimeCause { WitnessRuntimeCause::TypeError => "type-error", WitnessRuntimeCause::CrossRepresentationEquality => "cross-representation-equality", WitnessRuntimeCause::StringRealizationStraddle => "string-realization-straddle", + WitnessRuntimeCause::VariantRealizationRefused => "variant-realization-refused", WitnessRuntimeCause::PoolRootContributesNothing => "pool-root-contributes-nothing", WitnessRuntimeCause::PatternMatchFailure => "pattern-match-failure", WitnessRuntimeCause::RestResponseUndecodable => "rest-response-undecodable", @@ -11632,6 +11634,7 @@ impl WitnessRuntimeCause { WitnessRuntimeCause::CrossRepresentationEquality } E::StringRealizationStraddle { .. } => WitnessRuntimeCause::StringRealizationStraddle, + E::VariantRealizationRefused { .. } => WitnessRuntimeCause::VariantRealizationRefused, E::PoolRootContributesNothing { .. } => WitnessRuntimeCause::PoolRootContributesNothing, E::PatternMatchFailure { .. } => WitnessRuntimeCause::PatternMatchFailure, // A non-Bool guard is a type error at a located site; the variant carries the location, @@ -46427,7 +46430,8 @@ pub(crate) use emitted_closure_compile_host::{ fixture_closure_summary, fixture_discrimination_passed, fixture_discrimination_report, run_append_concat_form_discrimination, run_argv_word_list_splice_discrimination, run_empty_map_turbofish_discrimination, run_fixture_closure_discrimination, - run_function_value_adapter_discrimination, run_nested_refinement_cast_discrimination, + run_function_value_adapter_discrimination, run_local_true_false_coproduct_discrimination, + run_native_bool_variant_discrimination, run_nested_refinement_cast_discrimination, run_phantom_marker_identity_discrimination, run_shell_projection_arity_discrimination, FixtureClosureOutcome, }; diff --git a/src/v1/stage0/src/cli_run/census_heads.rs b/src/v1/stage0/src/cli_run/census_heads.rs index cf966b39dda..d492ad4088d 100644 --- a/src/v1/stage0/src/cli_run/census_heads.rs +++ b/src/v1/stage0/src/cli_run/census_heads.rs @@ -406,10 +406,12 @@ fn project_node(n: &Rc, base: i64, relabel: &[i64]) -> Result, St name, parent_enum, field_bindings, + parent_identity, }) => Some(Rc::new(MatchPattern::VariantPattern { name: name.clone(), parent_enum: parent_enum.clone(), field_bindings: list(field_bindings)?, + parent_identity: parent_identity.clone(), })), Some(MatchPattern::LitPattern { value: _ }) | Some(MatchPattern::Wildcard) => { match_pattern.clone() diff --git a/src/v1/stage0/src/compiler_tests.rs b/src/v1/stage0/src/compiler_tests.rs index b14e3e635e3..75c0370295b 100644 --- a/src/v1/stage0/src/compiler_tests.rs +++ b/src/v1/stage0/src/compiler_tests.rs @@ -1360,6 +1360,55 @@ mod compiler_tests { ); } + /// THE ARMS OF A NATIVELY REALIZED COPRODUCT, JUDGED BY RUSTC, AND THE IDENTITY CONTROL BESIDE IT. + /// + /// The subject is `v1.compiler.emit_rust` `rust_native_variant_spelling`: an arm of a + /// coproduct that realizes natively (std.types Bool over Rust `bool`) is spelled as the + /// carrier value its declaration-keyed row names, in value, pattern and nested-pattern + /// position. The first pair's control is that fixture and must COMPILE; before the rows it + /// emitted `Bool::True` against a `bool` and rustc refused it. The second pair's control is a + /// module-local coproduct whose arms are spelled True/False, which has no row and must keep its own enum -- the + /// evidence that the rows are keyed on identity rather than on the spelling. Both reds are + /// the route's own adjudicated red. + /// + /// #[ignore] AND WHY, on the same terms as the pairs beside it: each pair spawns cargo and + /// compiles two emitted crates. It is RUNNABLE ON DEMAND -- `cargo test --release -p + /// v1-compiler --lib native_bool_variant_fixture_closure_discrimination -- --ignored`. No CI + /// path invokes it (gunbc.rung_drop rust_unit_tests_off_the_merge_path); the emitted-bytes + /// half that does run on the floor is test.claim.native_variant_realization_witness_test. + #[test] + #[ignore] + fn native_bool_variant_fixture_closure_discrimination() { + let probe_root = crate::cli_run::local_emit_compile_probe_root().unwrap(); + for (label, pair) in [ + ( + "native-bool-variant", + crate::cli_run::run_native_bool_variant_discrimination(&probe_root), + ), + ( + "local-true-false-coproduct", + crate::cli_run::run_local_true_false_coproduct_discrimination(&probe_root), + ), + ] { + for line in crate::cli_run::fixture_discrimination_report(&pair) { + eprintln!("{} {}", label, line); + } + assert!( + crate::cli_run::fixture_closure_reached_rustc(&pair.red), + "{}: the red arm never reached a rustc verdict: {}", + label, + crate::cli_run::fixture_closure_summary(&pair.red) + ); + assert!( + crate::cli_run::fixture_discrimination_passed(&pair), + "{}: the control must COMPILE and the route red must still be refused by rustc in its own module; control={} red={}", + label, + crate::cli_run::fixture_closure_summary(&pair.green), + crate::cli_run::fixture_closure_summary(&pair.red) + ); + } + } + /// THE PHANTOM-MARKER POSITION PAIR, JUDGED BY RUSTC, THROUGH THE FIXTURE-CLOSURE ROUTE. /// /// NOT THE BROAD-VERSUS-POSITIONAL CLASSIFIER DISCRIMINATOR. That one's arms are two diff --git a/src/v1/stage0/src/coproduct_reflection.rs b/src/v1/stage0/src/coproduct_reflection.rs index dd56ab2fde5..313e7e4b288 100644 --- a/src/v1/stage0/src/coproduct_reflection.rs +++ b/src/v1/stage0/src/coproduct_reflection.rs @@ -2508,6 +2508,9 @@ mod parse_only_uppercase_variant_regression_tests { Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: "Parent".to_string(), + parent_identity: Rc::new( + crate::std_target_representation::VariantParentIdentity::VariantParentBeforeInference, + ), })), }), empty_node_list(), diff --git a/src/v1/stage0/src/data_initializer_identity.rs b/src/v1/stage0/src/data_initializer_identity.rs index f877acc5b34..7aa11507295 100644 --- a/src/v1/stage0/src/data_initializer_identity.rs +++ b/src/v1/stage0/src/data_initializer_identity.rs @@ -430,7 +430,7 @@ fn is_variant_value_binding(expr: &Rc) -> bool { fn variant_value_binding_parent_enum(expr: &Rc) -> Option { match expr_var_binding_kind(expr).as_deref() { - Some(VarBindingKind::VariantValueBinding { parent_enum }) => Some(parent_enum.clone()), + Some(VarBindingKind::VariantValueBinding { parent_enum, .. }) => Some(parent_enum.clone()), _ => None, } } diff --git a/src/v1/stage0/src/emitted_closure_compile_host.rs b/src/v1/stage0/src/emitted_closure_compile_host.rs index 69b58bb5c3c..04f6e37ef10 100644 --- a/src/v1/stage0/src/emitted_closure_compile_host.rs +++ b/src/v1/stage0/src/emitted_closure_compile_host.rs @@ -1781,6 +1781,45 @@ pub(crate) fn run_nested_refinement_cast_discrimination( } } +/// THE ARMS OF A NATIVELY REALIZED COPRODUCT, POSED TO RUSTC. `std.types` `Bool = True | False` +/// realizes as Rust `bool`, so `True`/`False` in value, pattern and nested-pattern position must be +/// spelled as that carrier's values, from `gunbc.rust_source_type_bindings` +/// `rust_source_variant_value_rows` keyed on the declaration. Before those rows the emitter wrote +/// `Bool::True` against a `bool`: accepted source, rustc E0308 +/// (`gunbc.recurring_failure_mode` `accepted_source_emits_uncompilable_target`). +#[cfg(test)] +const FIXTURE_NATIVE_BOOL_VARIANT_GREEN_PATH: &str = + "fixtures/fixture_closure_rustc/native_bool_variant_probe.dag"; + +/// THE IDENTITY CONTROL for the pair above: a module-local coproduct (`Verdict`) whose arms are +/// spelled `True`/`False` has no row and must keep its own enum. A lowering keyed on the arm +/// spelling would rewrite them to `true`/`false` against an enum, which rustc refuses. +#[cfg(test)] +const FIXTURE_LOCAL_TRUE_FALSE_COPRODUCT_GREEN_PATH: &str = + "fixtures/fixture_closure_rustc/local_true_false_coproduct_probe.dag"; + +/// Both native-variant controls, each against the route's own adjudicated red -- the same arm +/// runner and predicate as every pair beside them, not a second harness. +#[cfg(test)] +pub(crate) fn run_native_bool_variant_discrimination( + probe_root: &PrivateProbeRoot, +) -> FixtureDiscrimination { + FixtureDiscrimination { + green: fixture_arm_verdict(FIXTURE_NATIVE_BOOL_VARIANT_GREEN_PATH, probe_root), + red: fixture_arm_verdict(FIXTURE_RED_PATH, probe_root), + } +} + +#[cfg(test)] +pub(crate) fn run_local_true_false_coproduct_discrimination( + probe_root: &PrivateProbeRoot, +) -> FixtureDiscrimination { + FixtureDiscrimination { + green: fixture_arm_verdict(FIXTURE_LOCAL_TRUE_FALSE_COPRODUCT_GREEN_PATH, probe_root), + red: fixture_arm_verdict(FIXTURE_RED_PATH, probe_root), + } +} + /// THE PHANTOM-MARKER POSITION PAIR, POSED THROUGH THE ROUTE ABOVE (node adhoc-f044ad97-222). /// /// IT IS NOT THE BROAD-VERSUS-POSITIONAL CLASSIFIER DISCRIMINATOR, AND SAYING SO IS THE POINT. diff --git a/src/v1/stage0/src/emitted_population.rs b/src/v1/stage0/src/emitted_population.rs index 0183a2a8d2c..0438b0a3b7d 100644 --- a/src/v1/stage0/src/emitted_population.rs +++ b/src/v1/stage0/src/emitted_population.rs @@ -68,6 +68,7 @@ // src/std_induction.rs // src/std_integer.rs // src/std_interface_summary.rs +// src/std_kernel_type_name.rs // src/std_keyed_roster.rs // src/std_keyed_row.rs // src/std_literal_elaboration.rs diff --git a/src/v1/stage0/src/extdeps_languages_rust_representation.rs b/src/v1/stage0/src/extdeps_languages_rust_representation.rs index 5b789b0217f..6dda87d9cd9 100644 --- a/src/v1/stage0/src/extdeps_languages_rust_representation.rs +++ b/src/v1/stage0/src/extdeps_languages_rust_representation.rs @@ -6,7 +6,9 @@ pub use crate::extdeps_external_authority::ExternalAuthority; use crate::extdeps_uri::UriScheme::Https; pub use crate::extdeps_uri::{Uri, UriScheme}; pub use crate::std_coercion::TypeCheckpoint; -pub use crate::std_target_representation::{RepresentationSpelling, SourceTypeTargetBinding}; +pub use crate::std_target_representation::{ + RepresentationSpelling, RepresentationValue, SourceTypeTargetBinding, +}; use crate::std_types::Bool::*; pub use crate::std_types::{Bool, List, NonEmptyStr}; use crate::v1_rt; @@ -137,6 +139,41 @@ pub fn rust_exact_type_checkpoint( } } +pub fn rust_bool_true_value() -> Rc> { + thread_local! { + static CACHED: Rc> = { + Rc::new(RepresentationValue { + representation: RustRepresentation::RustBool, + value_spelling: "true".to_string(), + _phantom: std::marker::PhantomData, + }) + }; + } + CACHED.with(|c: &Rc>| c.clone()) +} + +pub fn rust_bool_false_value() -> Rc> { + thread_local! { + static CACHED: Rc> = { + Rc::new(RepresentationValue { + representation: RustRepresentation::RustBool, + value_spelling: "false".to_string(), + _phantom: std::marker::PhantomData, + }) + }; + } + CACHED.with(|c: &Rc>| c.clone()) +} + +pub fn rust_representation_values() -> Rc>>> { + thread_local! { + static CACHED: Rc>>> = { + Rc::new(vec![rust_bool_true_value(), rust_bool_false_value()]) + }; + } + CACHED.with(|c: &Rc>>>| c.clone()) +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct RustStdString; #[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] 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 43be126976a..2aea0720b08 100644 --- a/src/v1/stage0/src/gunbc_rust_source_type_bindings.rs +++ b/src/v1/stage0/src/gunbc_rust_source_type_bindings.rs @@ -5,13 +5,25 @@ pub use crate::extdeps_languages_rust_representation::RustRepresentation; use crate::extdeps_languages_rust_representation::RustRepresentation::{ RustBool, RustI64, RustSerdeJsonValue, RustStdString, RustUnit, RustVecU8, }; +pub use crate::extdeps_languages_rust_representation::{ + rust_bool_false_value, rust_bool_true_value, +}; pub use crate::std_decl_ref::decl_ref; pub use crate::std_decl_ref::DeclarationRef; +pub use crate::std_kernel_type_name::kernel_type_name; +pub use crate::std_kernel_type_name::KernelTypeNameAdmission; +use crate::std_kernel_type_name::KernelTypeNameAdmission::{ + KernelTypeNameAdmitted, NotAKernelTypeName, +}; use crate::std_target_representation::CheckpointRowDisposition::{ MigratedToExactBinding, ProvenUniqueKernelBinding, StillBareNameDebt, }; +use crate::std_target_representation::VariantParentKey::{ + VariantParentDeclaration, VariantParentKernelType, +}; pub use crate::std_target_representation::{ - CheckpointRowDisposition, CheckpointRowMigration, SourceTypeTargetBinding, + CheckpointRowDisposition, CheckpointRowMigration, RepresentationValue, SourceTypeTargetBinding, + SourceVariantTargetValue, VariantParentKey, }; use crate::std_types::Bool::*; pub use crate::std_types::{Bool, List, NonEmptyStr}; @@ -43,6 +55,68 @@ pub fn rust_source_type_binding_rows() -> Rc>>>| c.clone()) } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct BoolArmValue { + pub variant: NonEmptyStr, + pub value: Rc>, +} + +pub fn rust_bool_arm_values() -> Rc>> { + thread_local! { + static CACHED: Rc>> = { + Rc::new(vec![Rc::new(BoolArmValue { + variant: "True".to_string(), + value: rust_bool_true_value(), + }), Rc::new(BoolArmValue { + variant: "False".to_string(), + value: rust_bool_false_value(), + })]) + }; + } + CACHED.with(|c: &Rc>>| c.clone()) +} + +pub fn rust_bool_variant_rows( + parent: Rc, +) -> Rc>>> { + Rc::new({ + let mut __result = Vec::new(); + for a in rust_bool_arm_values().iter().cloned() { + __result.push(Rc::new(SourceVariantTargetValue { + parent: parent.clone(), + variant: a.variant.clone(), + value: a.value.clone(), + _phantom: std::marker::PhantomData, + })); + } + __result + }) +} + +pub fn rust_bool_kernel_variant_rows() -> Rc>>> +{ + match (*crate::std_kernel_type_name::kernel_type_name("Bool".to_string())).clone() { + KernelTypeNameAdmission::KernelTypeNameAdmitted { kernel_name: k, .. } => { + rust_bool_variant_rows(Rc::new(VariantParentKey::VariantParentKernelType { + kernel_name: k.clone(), + })) + } + KernelTypeNameAdmission::NotAKernelTypeName { name: _, .. } => Rc::new(vec![]), + } +} + +pub fn rust_source_variant_value_rows() -> Rc>>> +{ + thread_local! { + static CACHED: Rc>>> = { + v1_rt::concat(rust_bool_variant_rows(Rc::new(VariantParentKey::VariantParentDeclaration { + declaration: crate::std_decl_ref::decl_ref("std.types".to_string(), "Bool".to_string()), + })), rust_bool_kernel_variant_rows()) + }; + } + CACHED.with(|c: &Rc>>>| c.clone()) +} + pub fn rust_bound_declaration_refs() -> Rc>> { Rc::new({ let mut __result = Vec::new(); diff --git a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs index 13bc6d23fdc..cc1d4931371 100644 --- a/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs +++ b/src/v1/stage0/src/gunbc_stage0_crate_partition_generated.rs @@ -54,7 +54,7 @@ pub fn generated_partition_crate_rows() -> Rc package_name: "v1-stage0-std-core".to_string(), crate_dir: "src/v1/stage0_std_core".to_string(), kind: GeneratedPartitionCrateKind::GeneratedLayeredCoreCrate, - modules: Rc::new(vec!["std_content_hash".to_string(), "std_coercion".to_string(), "extdeps_currency_currency".to_string(), "std_decl_ref".to_string(), "std_keyed_row".to_string(), "std_keyed_roster".to_string(), "std_roster_frontier".to_string(), "std_dissolution".to_string(), "std_disposition".to_string(), "std_error_primitives".to_string(), "std_emit_model".to_string(), "std_magnitude".to_string(), "std_measure".to_string(), "std_types".to_string(), "std_unicode_types".to_string(), "std_algebra".to_string(), "std_nat".to_string(), "std_node".to_string(), "std_syntax".to_string(), "std_computation".to_string(), "std_termination".to_string(), "std_checked_arithmetic".to_string(), "std_induction".to_string(), "std_graph".to_string(), "extdeps_uri".to_string(), "extdeps_external_authority".to_string(), "extdeps_posix_clock_gettime".to_string(), "extdeps_ietf_http_semantics".to_string(), "std_process_termination".to_string(), "std_primitive_projection".to_string(), "extdeps_container_oci_digest".to_string(), "extdeps_units_dimensionless".to_string(), "extdeps_units_iec_80000_13".to_string(), "extdeps_units_iso8601".to_string(), "extdeps_units_iso_80000_3".to_string(), "std_occurrence_identity".to_string(), "std_source_annotation".to_string(), "std_target_representation".to_string(), "std_literal_elaboration".to_string(), "std_operator_realization".to_string(), "std_import".to_string(), "v1_std_core".to_string(), "gunbc_rust_emitted_edge".to_string()]), + modules: Rc::new(vec!["std_content_hash".to_string(), "std_coercion".to_string(), "extdeps_currency_currency".to_string(), "std_decl_ref".to_string(), "std_keyed_row".to_string(), "std_keyed_roster".to_string(), "std_roster_frontier".to_string(), "std_dissolution".to_string(), "std_disposition".to_string(), "std_error_primitives".to_string(), "std_emit_model".to_string(), "std_magnitude".to_string(), "std_measure".to_string(), "std_types".to_string(), "std_unicode_types".to_string(), "std_algebra".to_string(), "std_nat".to_string(), "std_node".to_string(), "std_syntax".to_string(), "std_computation".to_string(), "std_termination".to_string(), "std_checked_arithmetic".to_string(), "std_induction".to_string(), "std_graph".to_string(), "extdeps_uri".to_string(), "extdeps_external_authority".to_string(), "extdeps_posix_clock_gettime".to_string(), "extdeps_ietf_http_semantics".to_string(), "std_process_termination".to_string(), "std_primitive_projection".to_string(), "extdeps_container_oci_digest".to_string(), "extdeps_units_dimensionless".to_string(), "extdeps_units_iec_80000_13".to_string(), "extdeps_units_iso8601".to_string(), "extdeps_units_iso_80000_3".to_string(), "std_occurrence_identity".to_string(), "std_source_annotation".to_string(), "std_kernel_type_name".to_string(), "std_target_representation".to_string(), "std_literal_elaboration".to_string(), "std_operator_realization".to_string(), "std_import".to_string(), "v1_std_core".to_string(), "gunbc_rust_emitted_edge".to_string()]), reexport_packages: Rc::new(vec!["v1-stage0-runtime".to_string()]), carries_non_empty_wrappers: false, }), Rc::new(GeneratedPartitionCrateRow { diff --git a/src/v1/stage0/src/std_kernel_type_name.rs b/src/v1/stage0/src/std_kernel_type_name.rs new file mode 100644 index 00000000000..bf11202d386 --- /dev/null +++ b/src/v1/stage0/src/std_kernel_type_name.rs @@ -0,0 +1,33 @@ +// Generated by v1 compiler -- do not edit. +// Source module: std.kernel_type_name + +use self::KernelTypeNameAdmission::*; +pub use crate::std_types::is_kernel_type; +use crate::v1_rt; +use crate::v1_rt::{VecCompat, VecJoin}; +use crate::NonEmptyBTreeSet; +use crate::NonEmptyVec; +use im::{vector as vec, HashMap, OrdSet as BTreeSet, Vector as Vec}; +use std::rc::Rc; + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct KernelTypeName { + pub name: String, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum KernelTypeNameAdmission { + KernelTypeNameAdmitted { kernel_name: Rc }, + NotAKernelTypeName { name: String }, +} + +pub fn kernel_type_name(name: String) -> Rc { + if crate::std_types::is_kernel_type(name.clone()) { + Rc::new(KernelTypeNameAdmission::KernelTypeNameAdmitted { + kernel_name: Rc::new(KernelTypeName { name: name.clone() }), + }) + } else { + Rc::new(KernelTypeNameAdmission::NotAKernelTypeName { name: name.clone() }) + } +} diff --git a/src/v1/stage0/src/std_target_representation.rs b/src/v1/stage0/src/std_target_representation.rs index b0fc0742568..031fe341f30 100644 --- a/src/v1/stage0/src/std_target_representation.rs +++ b/src/v1/stage0/src/std_target_representation.rs @@ -3,8 +3,12 @@ use self::CheckpointRowDisposition::*; use self::ExactBindingResolution::*; +use self::VariantParentIdentity::*; +use self::VariantParentKey::*; +use self::VariantValueRealization::*; pub use crate::std_decl_ref::declaration_ref_eq; pub use crate::std_decl_ref::DeclarationRef; +pub use crate::std_kernel_type_name::KernelTypeName; use crate::std_types::Bool::*; pub use crate::std_types::{Bool, List, NonEmptyStr}; use crate::v1_rt; @@ -171,3 +175,235 @@ pub fn checkpoint_row_migration_for( .first() .cloned() } + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct RepresentationValue { + pub representation: R, + pub value_spelling: NonEmptyStr, + pub _phantom: std::marker::PhantomData, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum VariantParentKey { + VariantParentDeclaration { declaration: Rc }, + VariantParentKernelType { kernel_name: Rc }, +} + +pub fn variant_parent_key_eq(a: Rc, b: Rc) -> bool { + match (*a.clone()).clone() { + VariantParentKey::VariantParentDeclaration { + declaration: da, .. + } => match (*b.clone()).clone() { + VariantParentKey::VariantParentDeclaration { + declaration: db, .. + } => crate::std_decl_ref::declaration_ref_eq(da.clone(), db.clone()), + VariantParentKey::VariantParentKernelType { kernel_name: _, .. } => false, + }, + VariantParentKey::VariantParentKernelType { + kernel_name: ka, .. + } => match (*b.clone()).clone() { + VariantParentKey::VariantParentDeclaration { declaration: _, .. } => false, + VariantParentKey::VariantParentKernelType { + kernel_name: kb, .. + } => (ka.name.clone() == kb.name.clone()), + }, + } +} + +pub fn variant_parent_key_label(k: Rc) -> String { + match (*k.clone()).clone() { + VariantParentKey::VariantParentDeclaration { declaration: d, .. } => v1_rt::concat( + v1_rt::concat(d.module_path.clone(), ".".to_string()), + d.decl_name.clone(), + ), + VariantParentKey::VariantParentKernelType { kernel_name: n, .. } => { + v1_rt::concat("kernel ".to_string(), n.name.clone()) + } + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct SourceVariantTargetValue { + pub parent: Rc, + pub variant: NonEmptyStr, + pub value: Rc>, + pub _phantom: std::marker::PhantomData, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum VariantParentIdentity { + VariantParentIdentified { key: Rc }, + VariantParentUnrecovered { cause: NonEmptyStr }, + VariantParentBeforeInference, +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum VariantValueRealization { + VariantRealizesAsTargetValue { + value_spelling: NonEmptyStr, + }, + VariantRealizesStructurally, + VariantTargetValueUnbound { + parent: Rc, + variant: NonEmptyStr, + }, + VariantTargetValueAmbiguous { + parent: Rc, + variant: NonEmptyStr, + candidate_count: i64, + }, + VariantParentIdentityUnavailable { + cause: NonEmptyStr, + }, +} + +pub fn variant_rows_for( + key: Rc, + variant: String, + values: Rc>>>, +) -> Rc>>> { + Rc::new({ + let mut __result = Vec::new(); + for v in values.iter().cloned() { + if (variant_parent_key_eq(v.parent.clone(), key.clone()) + && (v.variant.clone() == variant.clone())) + { + __result.push(v); + } + } + __result + }) +} + +pub fn variant_value_from_hits( + key: Rc, + variant: String, + hits: Rc>>>, +) -> Rc { + { + let n = (hits.clone().len() as i64); + if (n.clone() == 1) { + match hits.clone().first().cloned() { + Some(v) => Rc::new(VariantValueRealization::VariantRealizesAsTargetValue { + value_spelling: v.value.clone().value_spelling.clone(), + }), + std::option::Option::None => { + Rc::new(VariantValueRealization::VariantTargetValueUnbound { + parent: key.clone(), + variant: variant.clone(), + }) + } + } + } else { + if (n.clone() == 0) { + Rc::new(VariantValueRealization::VariantTargetValueUnbound { + parent: key.clone(), + variant: variant.clone(), + }) + } else { + Rc::new(VariantValueRealization::VariantTargetValueAmbiguous { + parent: key.clone(), + variant: variant.clone(), + candidate_count: n.clone(), + }) + } + } + } +} + +pub fn variant_value_realization( + parent: Rc, + variant: String, + bindings: Rc>>>, + values: Rc>>>, + same_representation: impl Fn(R, R) -> bool + Clone, +) -> Rc { + match (*parent.clone()).clone() { + VariantParentIdentity::VariantParentBeforeInference => { + Rc::new(VariantValueRealization::VariantParentIdentityUnavailable { + cause: "the variant was never read by inference".to_string(), + }) + } + VariantParentIdentity::VariantParentUnrecovered { cause: c, .. } => { + Rc::new(VariantValueRealization::VariantParentIdentityUnavailable { cause: c.clone() }) + } + VariantParentIdentity::VariantParentIdentified { key: key, .. } => match (*key.clone()) + .clone() + { + VariantParentKey::VariantParentKernelType { kernel_name: _, .. } => { + let kernel_rows = Rc::new({ + let mut __result = Vec::new(); + for v in values.iter().cloned() { + if variant_parent_key_eq(v.parent.clone(), key.clone()) { + __result.push(v); + } + } + __result + }); + if ((kernel_rows.clone().len() as i64) == 0) { + Rc::new(VariantValueRealization::VariantRealizesStructurally) + } else { + variant_value_from_hits( + key.clone(), + variant.clone(), + variant_rows_for(key.clone(), variant.clone(), values.clone()), + ) + } + } + VariantParentKey::VariantParentDeclaration { declaration: d, .. } => { + match (*resolve_exact_binding(Some(d.clone()), bindings.clone())).clone() { + ExactBindingResolution::ExactBindingAbsent => { + Rc::new(VariantValueRealization::VariantRealizesStructurally) + } + ExactBindingResolution::ExactSourceIdentityUnavailable { cause: c, .. } => { + Rc::new(VariantValueRealization::VariantParentIdentityUnavailable { + cause: c.clone(), + }) + } + ExactBindingResolution::ExactBindingAmbiguous { + candidate_count: n, .. + } => Rc::new(VariantValueRealization::VariantTargetValueAmbiguous { + parent: key.clone(), + variant: variant.clone(), + candidate_count: n.clone(), + }), + ExactBindingResolution::ResolvedExactBinding { binding: b, .. } => { + variant_value_from_hits( + key.clone(), + variant.clone(), + Rc::new({ + let mut __result = Vec::new(); + for v in + variant_rows_for(key.clone(), variant.clone(), values.clone()) + .iter() + .cloned() + { + if same_representation( + v.value.clone().representation.clone(), + b.representation.clone(), + ) { + __result.push(v); + } + } + __result + }), + ) + } + } + } + }, + } +} + +pub fn variant_value_realization_refusal_message(r: Rc) -> Option { + match (*r.clone()).clone() { + VariantValueRealization::VariantRealizesAsTargetValue { value_spelling: _, .. } => std::option::Option::None, + VariantValueRealization::VariantRealizesStructurally => std::option::Option::None, + VariantValueRealization::VariantTargetValueUnbound { parent: p, variant: v, .. } => Some(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("variant realization: ".to_string(), variant_parent_key_label(p.clone())), " realizes natively on this target but its arm `".to_string()), v.clone()), "` has no target value row; the source spelling cannot be emitted against the native carrier".to_string())), + VariantValueRealization::VariantTargetValueAmbiguous { parent: p, variant: v, candidate_count: n, .. } => Some(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("variant realization: arm `".to_string(), v.clone()), "` of ".to_string()), variant_parent_key_label(p.clone())), " has ".to_string()), (n.clone()).to_string()), " target value rows (corpus authoring defect)".to_string())), + VariantValueRealization::VariantParentIdentityUnavailable { cause: c, .. } => Some(v1_rt::concat(v1_rt::concat("variant realization: the coproduct this variant belongs to was not recovered (".to_string(), c.clone()), "), so whether it realizes natively cannot be decided".to_string())), +} +} diff --git a/src/v1/stage0/src/v1_compiler_coercion.rs b/src/v1/stage0/src/v1_compiler_coercion.rs index d7c3bb2202f..58312be062e 100644 --- a/src/v1/stage0/src/v1_compiler_coercion.rs +++ b/src/v1/stage0/src/v1_compiler_coercion.rs @@ -10,15 +10,17 @@ pub use crate::extdeps_languages_python_types::{ python_algebra_inhabitants, python_callable, python_cast_syntax, python_optional_template, python_type_checkpoints, }; -pub use crate::extdeps_languages_rust_representation::rust_exact_type_checkpoint; pub use crate::extdeps_languages_rust_representation::RustRepresentation; use crate::extdeps_languages_rust_representation::RustRepresentation::*; +pub use crate::extdeps_languages_rust_representation::{ + rust_exact_type_checkpoint, rust_representation_eq, +}; pub use crate::extdeps_languages_rust_types::{ rust_algebra_inhabitants, rust_callable, rust_cast_syntax, rust_optional_template, rust_type_checkpoints, }; pub use crate::gunbc_rust_source_type_bindings::{ - checkpoint_row_migration_rows, rust_source_type_binding_rows, + checkpoint_row_migration_rows, rust_source_type_binding_rows, rust_source_variant_value_rows, }; use crate::std_coercion::RealizationGround::{ GroundedByCheckpointRow, GroundedByHostNumericAlias, GroundedByUnidentifiedBareRow, @@ -37,12 +39,17 @@ pub use crate::std_coercion::{ TypeCheckpoint, TypeDeclarationProvenance, TypeRealizationDecision, }; pub use crate::std_decl_ref::DeclarationRef; -pub use crate::std_target_representation::ExactBindingResolution; use crate::std_target_representation::ExactBindingResolution::{ ExactBindingAbsent, ExactBindingAmbiguous, ExactSourceIdentityUnavailable, ResolvedExactBinding, }; +use crate::std_target_representation::VariantParentIdentity::*; +use crate::std_target_representation::VariantValueRealization::*; pub use crate::std_target_representation::{ checkpoint_row_disposition_keeps_bare_row, checkpoint_row_migration_for, resolve_exact_binding, + variant_value_realization, +}; +pub use crate::std_target_representation::{ + ExactBindingResolution, VariantParentIdentity, VariantValueRealization, }; pub use crate::std_types::NonEmptyStr; pub use crate::std_types::{canonical_container_names, container_template_algebra}; @@ -823,3 +830,34 @@ pub fn extract_coercion_tests() -> Rc>> { template_application_tests(), ) } + +pub fn rust_variant_value_realization( + parent: Rc, + variant: String, +) -> Rc { + crate::std_target_representation::variant_value_realization( + parent.clone(), + variant.clone(), + rust_source_type_binding_rows(), + rust_source_variant_value_rows(), + |a, b| { + crate::extdeps_languages_rust_representation::rust_representation_eq( + a.clone(), + b.clone(), + ) + }, + ) +} + +pub fn rust_variant_arm_is_bound_somewhere(variant: String) -> bool { + { + let mut __found = false; + for v in rust_source_variant_value_rows().iter().cloned() { + if (v.variant.clone() == variant.clone()) { + __found = true; + break; + } + } + __found + } +} diff --git a/src/v1/stage0/src/v1_compiler_compile.rs b/src/v1/stage0/src/v1_compiler_compile.rs index 2e0355ffe1c..5463fdd4572 100644 --- a/src/v1/stage0/src/v1_compiler_compile.rs +++ b/src/v1/stage0/src/v1_compiler_compile.rs @@ -682,9 +682,7 @@ pub fn function_value_target( crate::v1_std_core::authored_name_at(source_indices.clone(), texpr.clone()), ), VarBindingKind::LocalValueBinding => std::option::Option::None, - VarBindingKind::VariantValueBinding { parent_enum: _, .. } => { - std::option::Option::None - } + VarBindingKind::VariantValueBinding { .. } => std::option::Option::None, VarBindingKind::MatchBoundBinding => std::option::Option::None, VarBindingKind::ServiceValueBinding => std::option::Option::None, }, @@ -1692,9 +1690,7 @@ pub fn var_binding_kind_name(value: Rc) -> String { match (*value.clone()).clone() { VarBindingKind::LocalValueBinding => "LocalValueBinding".to_string(), VarBindingKind::FunctionValueBinding => "FunctionValueBinding".to_string(), - VarBindingKind::VariantValueBinding { parent_enum: _, .. } => { - "VariantValueBinding".to_string() - } + VarBindingKind::VariantValueBinding { .. } => "VariantValueBinding".to_string(), VarBindingKind::MatchBoundBinding => "MatchBoundBinding".to_string(), VarBindingKind::ServiceValueBinding => "ServiceValueBinding".to_string(), } @@ -2480,15 +2476,14 @@ pub fn serialize_expr_data( ), ), match (*inner.clone()).clone() { - VarBindingKind::VariantValueBinding { - parent_enum: parent_enum, - .. - } => v1_rt::concat( - ", \"parent_enum\": ".to_string(), - crate::v1_compiler_dag_collect_support::json_quote( - parent_enum.clone(), - ), - ), + VarBindingKind::VariantValueBinding { parent_enum, .. } => { + v1_rt::concat( + ", \"parent_enum\": ".to_string(), + crate::v1_compiler_dag_collect_support::json_quote( + parent_enum.clone(), + ), + ) + } _ => "".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 4b291bad0e3..d3919286864 100644 --- a/src/v1/stage0/src/v1_compiler_compiler_tests_rust.rs +++ b/src/v1/stage0/src/v1_compiler_compiler_tests_rust.rs @@ -64,6 +64,10 @@ pub fn ct_nested_refinement_cast_fixture_closure_discrimination_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(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" /// REPRESENTATION-IDENTICAL REFINEMENT AND BRAND CASTS, JUDGED BY RUSTC (gunbc#10266).\n".to_string(), " ///\n".to_string()), " /// The subject is `v1.compiler.emit` `cast_representation_identical`: a cast whose source and\n".to_string()), " /// target are ONE host carrier reached through transparent refinement, alias and brand edges\n".to_string()), " /// asks the target for no operation, so the emission must be the operand unchanged. The\n".to_string()), " /// fixture exercises six such casts across three aliases in BOTH directions, plus one genuine\n".to_string()), " /// numeric conversion that must still go through the target cast syntax.\n".to_string()), " ///\n".to_string()), " /// WHY THIS SUBJECT NEEDS RUSTC AND NOT A SUBSTRING. `test.claim`\n".to_string()), " /// `emitter_nested_refinement_cast_witness_test` asserts the ABSENCE of the fabricated\n".to_string()), " /// unsupported-cast text, and absence is all a spelling oracle can honestly assert here:\n".to_string()), " /// asserting the presence of a particular replacement would pin one rendering of \"the operand\n".to_string()), " /// unchanged\". Whether the replacement TYPE-CHECKS as the declared return is a meaning-level\n".to_string()), " /// question, and the never type is exactly what let the defective form pass a type check.\n".to_string()), " ///\n".to_string()), " /// THE RED ARM IS THE ROUTE'S OWN, so this pair proves the route can still fail using the\n".to_string()), " /// discrimination already adjudicated for it rather than a fresh unadjudicated arm.\n".to_string()), " ///\n".to_string()), " /// #[ignore] AND WHY, on the same terms as the two pairs beside it: this arm spawns cargo and\n".to_string()), " /// compiles two emitted crates, which is minutes rather than milliseconds. It is ENROLLED AND\n".to_string()), " /// OPT-IN -- `cargo test --release -p v1-compiler --lib\n".to_string()), " /// nested_refinement_cast_fixture_closure_discrimination -- --ignored`. An #[ignore] is a cost\n".to_string()), " /// decision and NOT a rung: nothing here may be cited as coverage that executes on the merge\n".to_string()), " /// path.\n".to_string()), " #[test]\n".to_string()), " #[ignore]\n".to_string()), " fn nested_refinement_cast_fixture_closure_discrimination() {\n".to_string()), " let probe_root = crate::cli_run::local_emit_compile_probe_root().unwrap();\n".to_string()), " let pair = crate::cli_run::run_nested_refinement_cast_discrimination(&probe_root);\n".to_string()), " for line in crate::cli_run::fixture_discrimination_report(&pair) {\n".to_string()), " eprintln!(\"nested-refinement-cast {}\", line);\n".to_string()), " }\n".to_string()), " assert!(\n".to_string()), " crate::cli_run::fixture_closure_reached_rustc(&pair.red),\n".to_string()), " \"the red arm never reached a rustc verdict, so nothing about the emitted bytes was measured: {}\",\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.red)\n".to_string()), " );\n".to_string()), " assert!(\n".to_string()), " crate::cli_run::fixture_discrimination_passed(&pair),\n".to_string()), " \"the representation-identical cast control must COMPILE -- an unsupported-cast panic emitted for any of its six casts is a type error at the declared return -- and the route red must still be refused by rustc in its own emitted module with the claimed error class; control={} red={} attribution={:?} diagnostic={:?}\",\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.green),\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.red),\n".to_string()), " crate::cli_run::fixture_closure_attributed_line(&pair.red),\n".to_string()), " crate::cli_run::fixture_closure_attributed_diagnostic(&pair.red)\n".to_string()), " );\n".to_string()), " }\n\n".to_string()) } +pub fn ct_native_bool_variant_fixture_closure_discrimination_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(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" /// THE ARMS OF A NATIVELY REALIZED COPRODUCT, JUDGED BY RUSTC, AND THE IDENTITY CONTROL BESIDE IT.\n".to_string(), " ///\n".to_string()), " /// The subject is `v1.compiler.emit_rust` `rust_native_variant_spelling`: an arm of a\n".to_string()), " /// coproduct that realizes natively (std.types Bool over Rust `bool`) is spelled as the\n".to_string()), " /// carrier value its declaration-keyed row names, in value, pattern and nested-pattern\n".to_string()), " /// position. The first pair's control is that fixture and must COMPILE; before the rows it\n".to_string()), " /// emitted `Bool::True` against a `bool` and rustc refused it. The second pair's control is a\n".to_string()), " /// module-local coproduct whose arms are spelled True/False, which has no row and must keep its own enum -- the\n".to_string()), " /// evidence that the rows are keyed on identity rather than on the spelling. Both reds are\n".to_string()), " /// the route's own adjudicated red.\n".to_string()), " ///\n".to_string()), " /// #[ignore] AND WHY, on the same terms as the pairs beside it: each pair spawns cargo and\n".to_string()), " /// compiles two emitted crates. It is RUNNABLE ON DEMAND -- `cargo test --release -p\n".to_string()), " /// v1-compiler --lib native_bool_variant_fixture_closure_discrimination -- --ignored`. No CI\n".to_string()), " /// path invokes it (gunbc.rung_drop rust_unit_tests_off_the_merge_path); the emitted-bytes\n".to_string()), " /// half that does run on the floor is test.claim.native_variant_realization_witness_test.\n".to_string()), " #[test]\n".to_string()), " #[ignore]\n".to_string()), " fn native_bool_variant_fixture_closure_discrimination() {\n".to_string()), " let probe_root = crate::cli_run::local_emit_compile_probe_root().unwrap();\n".to_string()), " for (label, pair) in [\n".to_string()), " (\"native-bool-variant\", crate::cli_run::run_native_bool_variant_discrimination(&probe_root)),\n".to_string()), " (\"local-true-false-coproduct\", crate::cli_run::run_local_true_false_coproduct_discrimination(&probe_root)),\n".to_string()), " ] {\n".to_string()), " for line in crate::cli_run::fixture_discrimination_report(&pair) {\n".to_string()), " eprintln!(\"{} {}\", label, line);\n".to_string()), " }\n".to_string()), " assert!(\n".to_string()), " crate::cli_run::fixture_closure_reached_rustc(&pair.red),\n".to_string()), " \"{}: the red arm never reached a rustc verdict: {}\",\n".to_string()), " label,\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.red)\n".to_string()), " );\n".to_string()), " assert!(\n".to_string()), " crate::cli_run::fixture_discrimination_passed(&pair),\n".to_string()), " \"{}: the control must COMPILE and the route red must still be refused by rustc in its own module; control={} red={}\",\n".to_string()), " label,\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.green),\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.red)\n".to_string()), " );\n".to_string()), " }\n".to_string()), " }\n\n".to_string()) +} + pub fn ct_phantom_marker_identity_fixture_closure_discrimination_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(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(" /// THE PHANTOM-MARKER POSITION PAIR, JUDGED BY RUSTC, THROUGH THE FIXTURE-CLOSURE ROUTE.\n".to_string(), " ///\n".to_string()), " /// NOT THE BROAD-VERSUS-POSITIONAL CLASSIFIER DISCRIMINATOR. That one's arms are two\n".to_string()), " /// COMPILER behaviours over ONE source, and no pair of fixture FILES can be those arms --\n".to_string()), " /// files vary the source and hold the compiler fixed. This does not discharge that ceiling\n".to_string()), " /// row, which stays at MeaningDiscriminatorExecutedNotEnrolled (codex review 60742).\n".to_string()), " ///\n".to_string()), " /// The subject is `v1.compiler.emit_rust` `rust_type_arg_identity_spelling`: a type argument's\n".to_string()), " /// Rust identity is decided from the declaration visible in the module, never from the\n".to_string()), " /// syntactic position that happened to render it. `test.claim`\n".to_string()), " /// `phantom_marker_type_argument_identity_witness` already adjudicates the SPELLING half of\n".to_string()), " /// that decision across every outer renderer and STAYS ENROLLED (DESIGN 4b(4): a climb deletes\n".to_string()), " /// lower-rung production machinery, never the evidence). This arm is the half that witness\n".to_string()), " /// declares it cannot reach -- `compile_dag_rust_emit_check` stops at emitted TEXT and never\n".to_string()), " /// invokes rustc, which is what pinned that class at SourceToEmittedTextHonestyOnly.\n".to_string()), " ///\n".to_string()), " /// WHAT THE TWO ARMS ARE, AND WHAT THEY DO NOT ISOLATE. Both declare the same coproduct\n".to_string()), " /// `Marker = Alpha | Beta`. The control puts `Alpha` and `Beta` in the RULED POSITION --\n".to_string()), " /// arguments of an applied type node -- where they become distinct zero-sized markers, and\n".to_string()), " /// its emitted crate COMPILES. The red puts `Alpha` in a NON-APPLIED position, a record\n".to_string()), " /// field, and returns that `Alpha`-typed field from a function declared to return `Marker`;\n".to_string()), " /// its emitted crate is REFUSED at that return. So a green here is not \"some crate compiled\"\n".to_string()), " /// and the red is not \"something in the tree is broken\".\n".to_string()), " ///\n".to_string()), " /// THE PAIR DOES NOT ISOLATE POSITION AS THE SOLE CAUSE, and an earlier revision of this\n".to_string()), " /// description claimed it did (native comment review 5120541804). The arms also differ in\n".to_string()), " /// their RETURN CONTRACT -- the control returns an `Int` read through a wrapper -- and the\n".to_string()), " /// measured E0308 lands AT the return, so the return contract is load-bearing for the refusal\n".to_string()), " /// rather than incidental. What the pair characterizes is two CONCRETE CONSTRUCTIONS, not a\n".to_string()), " /// single-variable experiment over position.\n".to_string()), " ///\n".to_string()), " /// THE RED IS A KNOWN HOLE, NOT A WALL WORKING, and it is named as one so nobody reads its red\n".to_string()), " /// as coverage. It is `gunbc.recurring_failure_mode` `accepted_source_emits_uncompilable_target`\n".to_string()), " /// at that row's own filed FIRST instance, which the row records was never committed to this\n".to_string()), " /// repository as a runnable file. It is committed here as one. When the wall climbs -- type\n".to_string()), " /// position resolution consulting the TYPE namespace alone -- the arm flips to SourceRefused\n".to_string()), " /// and is KEPT; what changes is this pair's expectation, not the fixture's existence.\n".to_string()), " ///\n".to_string()), " /// WHAT RUSTC ACTUALLY SAID, AND WHY IT IS RECORDED HERE. The emitted red module carries BOTH\n".to_string()), " /// an `Alpha` type and a `Marker::Alpha` variant: the field annotation binds the former, the\n".to_string()), " /// declared return wants the latter, and the refusal lands at the parent boundary as E0308,\n".to_string()), " /// `expected Marker, found Alpha`. E0573 was predicted from the ceiling row and did NOT\n".to_string()), " /// reproduce -- both arms declare their markers LOCALLY, so neither exercises the\n".to_string()), " /// imported-marker construction where those classifiers diverge, and the prediction was\n".to_string()), " /// mis-scoped from the start. The expectation is the route's adjudicated class. See\n".to_string()), " /// `run_phantom_marker_identity_discrimination` for the full diagnostic and for what is\n".to_string()), " /// deliberately not claimed from one construction.\n".to_string()), " ///\n".to_string()), " /// #[ignore] AND WHY, on the same terms as the three pairs beside it: this arm spawns cargo\n".to_string()), " /// and compiles two emitted crates, which is minutes rather than milliseconds. It is ENROLLED\n".to_string()), " /// AND OPT-IN -- `cargo test --release -p v1-compiler --lib\n".to_string()), " /// phantom_marker_identity_fixture_closure_discrimination -- --ignored`. An #[ignore] is a\n".to_string()), " /// cost decision and NOT a rung: nothing here may be cited as coverage that executes on the\n".to_string()), " /// merge path, and the phantom-marker ceiling carrier may not be flipped to\n".to_string()), " /// MeaningDiscriminatorEnrolled on the strength of it.\n".to_string()), " #[test]\n".to_string()), " #[ignore]\n".to_string()), " fn phantom_marker_identity_fixture_closure_discrimination() {\n".to_string()), " let probe_root = crate::cli_run::local_emit_compile_probe_root().unwrap();\n".to_string()), " let pair = crate::cli_run::run_phantom_marker_identity_discrimination(&probe_root);\n".to_string()), " for line in crate::cli_run::fixture_discrimination_report(&pair) {\n".to_string()), " eprintln!(\"phantom-marker-identity {}\", line);\n".to_string()), " }\n".to_string()), " assert!(\n".to_string()), " crate::cli_run::fixture_closure_reached_rustc(&pair.red),\n".to_string()), " \"the red arm never reached a rustc verdict, so nothing about the emitted bytes was measured: {}\",\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.red)\n".to_string()), " );\n".to_string()), " assert!(\n".to_string()), " crate::cli_run::fixture_discrimination_passed(&pair),\n".to_string()), " \"the applied-marker fixture must COMPILE, and the non-applied-field-plus-parent-return fixture must reach rustc and be refused in its own emitted module with the attributed E0308 this pair claims; control={} red={} attribution={:?} diagnostic={:?}\",\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.green),\n".to_string()), " crate::cli_run::fixture_closure_summary(&pair.red),\n".to_string()), " crate::cli_run::fixture_closure_attributed_line(&pair.red),\n".to_string()), " crate::cli_run::fixture_closure_attributed_diagnostic(&pair.red)\n".to_string()), " );\n".to_string()), " }\n\n".to_string()) } @@ -418,5 +422,5 @@ pub fn ct_test_reference_orphan_row_test() -> String { } pub fn compiler_tests_source() -> 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(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(ct_module_header(), ct_workspace_helpers()), ct_file_discovery_helpers()), ct_source_builders()), ct_tokenizer_tests()), ct_parse_tests()), ct_test_marker_item_kind_test()), ct_test_reference_wall_test()), ct_test_reference_import_all_test()), ct_test_reference_orphan_row_test()), ct_tco_tail_call_assigns_every_loop_slot_test()), ct_pipeline_test()), ct_entry_point_absent_refusal_test()), ct_import_lines_follow_resolved_binding_identity_test()), ct_generic_optional_over_a_type_application_keeps_the_optional_test()), ct_pub_use_crate_lines_two_emission_byte_identity_test()), ct_overlapping_use_line_dedupe_permutation_test()), ct_fixture_closure_rustc_discrimination_test()), ct_evaluation_budget_consequence_falsifier_test()), ct_function_value_adapter_fixture_closure_discrimination_test()), ct_nested_refinement_cast_fixture_closure_discrimination_test()), ct_phantom_marker_identity_fixture_closure_discrimination_test()), ct_empty_map_turbofish_fixture_closure_discrimination_test()), ct_argv_word_list_splice_fixture_closure_discrimination_test()), ct_append_concat_form_fixture_closure_discrimination_test()), ct_shell_projection_arity_fixture_closure_discrimination_test()), ct_unlisted_import_use_witness_test()), ct_call_shape_wall_witness_test()), ct_call_deficit_red_witness_test()), ct_call_shape_duplicate_wall_witness_test()), ct_function_value_named_application_controls_witness_test()), ct_effect_summary_refusals_carry_their_call_site_test()), ct_function_value_field_method_known_hole_probe_test()), ct_shell_service_output_projection_test()), ct_shell_service_unmodeled_output_key_refusal_test()), ct_shell_service_exit_error_arm_boxed_test()), ct_function_value_adapter_bound_alignment_control_test()), ct_rendered_leaf_occurrence_identity_test()), ct_rendered_leaf_occurrence_identity_pipeline_test()), ct_method_existence_wall_witness_test()), ct_declared_type_conformance_witness_test()), ct_direct_call_formal_authority_carrier_test()), ct_sole_constructor_test()), ct_constructor_call_admission_test()), ct_constructor_call_admission_same_module_sibling_test()), ct_constructor_call_admission_function_value_test()), ct_constructor_call_admission_zero_arity_test()), ct_constructor_call_admission_shadowing_test()), ct_constructor_call_admission_qualified_caller_test()), ct_sole_constructor_fieldless_witness_test()), ct_contracts_sidecar_witness_test()), ct_self_parse_all_test()), ct_self_resolve_test()), ct_self_compile_test()), ct_self_compile_cargo_check_test()), ct_type_size_test()), ct_coercion_tests()), ct_profile_helpers()), ct_profile_self_compile_test()), ct_profile_full_pipeline_test()), ct_profile_reconcile_test()), ct_module_footer()) + 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(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(ct_module_header(), ct_workspace_helpers()), ct_file_discovery_helpers()), ct_source_builders()), ct_tokenizer_tests()), ct_parse_tests()), ct_test_marker_item_kind_test()), ct_test_reference_wall_test()), ct_test_reference_import_all_test()), ct_test_reference_orphan_row_test()), ct_tco_tail_call_assigns_every_loop_slot_test()), ct_pipeline_test()), ct_entry_point_absent_refusal_test()), ct_import_lines_follow_resolved_binding_identity_test()), ct_generic_optional_over_a_type_application_keeps_the_optional_test()), ct_pub_use_crate_lines_two_emission_byte_identity_test()), ct_overlapping_use_line_dedupe_permutation_test()), ct_fixture_closure_rustc_discrimination_test()), ct_evaluation_budget_consequence_falsifier_test()), ct_function_value_adapter_fixture_closure_discrimination_test()), ct_nested_refinement_cast_fixture_closure_discrimination_test()), ct_native_bool_variant_fixture_closure_discrimination_test()), ct_phantom_marker_identity_fixture_closure_discrimination_test()), ct_empty_map_turbofish_fixture_closure_discrimination_test()), ct_argv_word_list_splice_fixture_closure_discrimination_test()), ct_append_concat_form_fixture_closure_discrimination_test()), ct_shell_projection_arity_fixture_closure_discrimination_test()), ct_unlisted_import_use_witness_test()), ct_call_shape_wall_witness_test()), ct_call_deficit_red_witness_test()), ct_call_shape_duplicate_wall_witness_test()), ct_function_value_named_application_controls_witness_test()), ct_effect_summary_refusals_carry_their_call_site_test()), ct_function_value_field_method_known_hole_probe_test()), ct_shell_service_output_projection_test()), ct_shell_service_unmodeled_output_key_refusal_test()), ct_shell_service_exit_error_arm_boxed_test()), ct_function_value_adapter_bound_alignment_control_test()), ct_rendered_leaf_occurrence_identity_test()), ct_rendered_leaf_occurrence_identity_pipeline_test()), ct_method_existence_wall_witness_test()), ct_declared_type_conformance_witness_test()), ct_direct_call_formal_authority_carrier_test()), ct_sole_constructor_test()), ct_constructor_call_admission_test()), ct_constructor_call_admission_same_module_sibling_test()), ct_constructor_call_admission_function_value_test()), ct_constructor_call_admission_zero_arity_test()), ct_constructor_call_admission_shadowing_test()), ct_constructor_call_admission_qualified_caller_test()), ct_sole_constructor_fieldless_witness_test()), ct_contracts_sidecar_witness_test()), ct_self_parse_all_test()), ct_self_resolve_test()), ct_self_compile_test()), ct_self_compile_cargo_check_test()), ct_type_size_test()), ct_coercion_tests()), ct_profile_helpers()), ct_profile_self_compile_test()), ct_profile_full_pipeline_test()), ct_profile_reconcile_test()), ct_module_footer()) } diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index fa107e671cb..4e688234cee 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -361,10 +361,7 @@ pub fn emit_simple_expr( binding_kind: bk, .. } => match bk.clone().as_deref().cloned() { Some(VarBindingKind::MatchBoundBinding) => false, - Some(VarBindingKind::VariantValueBinding { - parent_enum: _, - .. - }) => false, + Some(VarBindingKind::VariantValueBinding { .. }) => false, _ => true, }, _ => false, diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index a5c5a21c1a4..b0401ada791 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -115,10 +115,20 @@ use crate::std_syntax::AlgebraFieldKind::*; use crate::std_syntax::BinOp::*; use crate::std_syntax::LiteralValue::*; pub use crate::std_syntax::{AlgebraFieldKind, BinOp, LiteralValue}; -pub use crate::std_target_representation::ExactBindingResolution; +pub use crate::std_target_representation::variant_value_realization_refusal_message; use crate::std_target_representation::ExactBindingResolution::{ ExactBindingAbsent, ExactBindingAmbiguous, ExactSourceIdentityUnavailable, ResolvedExactBinding, }; +use crate::std_target_representation::VariantParentIdentity::{ + VariantParentBeforeInference, VariantParentUnrecovered, +}; +use crate::std_target_representation::VariantValueRealization::{ + VariantParentIdentityUnavailable, VariantRealizesAsTargetValue, VariantRealizesStructurally, + VariantTargetValueAmbiguous, VariantTargetValueUnbound, +}; +pub use crate::std_target_representation::{ + ExactBindingResolution, VariantParentIdentity, VariantValueRealization, +}; pub use crate::std_types::SourceSpan; pub use crate::std_types::{container_template_algebra, is_container_type, is_kernel_type}; use crate::v1_compiler_artifact::RenderTarget::Rust; @@ -131,7 +141,8 @@ pub use crate::v1_compiler_closure_stub_v2_std_text_rust::closure_stub_v2_std_te pub use crate::v1_compiler_coercion::{ coerce_primitive_type, declaration_realization, declaration_realizes_natively_on_rust, is_copy, provenance_declares_structurally, realization_host_numeric_spelling, - realization_is_host_numeric, realized_checkpoint, rust_lookup_exact_binding, target_callable, + realization_is_host_numeric, realized_checkpoint, rust_lookup_exact_binding, + rust_variant_arm_is_bound_somewhere, rust_variant_value_realization, target_callable, type_realization_decision, type_reference_realization, }; pub use crate::v1_compiler_compiler_tests_rust::compiler_tests_source; @@ -20953,17 +20964,24 @@ pub fn emit_pattern( name: n, parent_enum, field_bindings: fbs, + parent_identity: identity, .. - } => emit_variant_pattern( - n.clone(), - parent_enum.clone(), - fbs.clone(), - path_prefix.clone(), - shared_types.clone(), - scrut_type.clone(), - source_indices.clone(), - emit_info.clone(), - ), + } => match rust_native_variant_spelling( + identity.clone(), + crate::v1_std_core::qualified_last_segment(n.clone()), + ) { + Some(native) => native.clone(), + std::option::Option::None => emit_variant_pattern( + n.clone(), + parent_enum.clone(), + fbs.clone(), + path_prefix.clone(), + shared_types.clone(), + scrut_type.clone(), + source_indices.clone(), + emit_info.clone(), + ), + }, MatchPattern::Wildcard => "_".to_string(), } } @@ -21853,18 +21871,25 @@ pub fn emit_pattern_rc_aware( name: n, parent_enum, field_bindings: fbs, + parent_identity: identity, .. - } => emit_variant_pattern_rc_aware( - n.clone(), - parent_enum.clone(), - fbs.clone(), - path_prefix.clone(), - rc_analysis.clone(), - shared_types.clone(), - scrut_type.clone(), - source_indices.clone(), - emit_info.clone(), - ), + } => match rust_native_variant_spelling( + identity.clone(), + crate::v1_std_core::qualified_last_segment(n.clone()), + ) { + Some(native) => native.clone(), + std::option::Option::None => emit_variant_pattern_rc_aware( + n.clone(), + parent_enum.clone(), + fbs.clone(), + path_prefix.clone(), + rc_analysis.clone(), + shared_types.clone(), + scrut_type.clone(), + source_indices.clone(), + emit_info.clone(), + ), + }, MatchPattern::Wildcard => "_".to_string(), } } @@ -22608,14 +22633,80 @@ pub fn is_simple_type_node( is_rust_value_type(n.clone(), source_indices.clone()) } -pub fn variant_parent_from_binding_kind( +pub fn rust_native_variant_spelling( + parent: Rc, + leaf_name: String, +) -> Option { + match (*parent.clone()).clone() { + VariantParentIdentity::VariantParentBeforeInference => Some(emit_rust_compile_error_expr(v1_rt::concat(v1_rt::concat("variant realization: `".to_string(), leaf_name.clone()), "` reached emission without inference having read which coproduct it belongs to (VariantParentBeforeInference); an unread occurrence is refused rather than rendered as either the native value or its enum path".to_string()))), + _ => rust_native_variant_spelling_of_read(parent.clone(), leaf_name.clone()), +} +} + +pub fn rust_native_variant_spelling_of_read( + parent: Rc, + leaf_name: String, +) -> Option { + { + let r = crate::v1_compiler_coercion::rust_variant_value_realization( + parent.clone(), + leaf_name.clone(), + ); + match (*r.clone()).clone() { + VariantValueRealization::VariantRealizesAsTargetValue { + value_spelling: s, .. + } => Some(s.clone()), + VariantValueRealization::VariantRealizesStructurally => std::option::Option::None, + VariantValueRealization::VariantParentIdentityUnavailable { cause: _, .. } => { + if crate::v1_compiler_coercion::rust_variant_arm_is_bound_somewhere( + leaf_name.clone(), + ) { + match crate::std_target_representation::variant_value_realization_refusal_message(r.clone()) { + Some(m) => Some(emit_rust_compile_error_expr(m.clone())), + std::option::Option::None => std::option::Option::None, +} + } else { + std::option::Option::None + } + } + VariantValueRealization::VariantTargetValueUnbound { .. } => { + match crate::std_target_representation::variant_value_realization_refusal_message( + r.clone(), + ) { + Some(m) => Some(emit_rust_compile_error_expr(m.clone())), + std::option::Option::None => std::option::Option::None, + } + } + VariantValueRealization::VariantTargetValueAmbiguous { .. } => { + match crate::std_target_representation::variant_value_realization_refusal_message( + r.clone(), + ) { + Some(m) => Some(emit_rust_compile_error_expr(m.clone())), + std::option::Option::None => std::option::Option::None, + } + } + } + } +} + +pub fn rust_native_variant_spelling_of_binding( binding_kind: Option>, + leaf_name: String, ) -> Option { match binding_kind.clone().as_deref().cloned() { Some(VarBindingKind::VariantValueBinding { - parent_enum: parent_enum, + parent_identity: identity, .. - }) => Some(parent_enum.clone()), + }) => rust_native_variant_spelling(identity.clone(), leaf_name.clone()), + _ => std::option::Option::None, + } +} + +pub fn variant_parent_from_binding_kind( + binding_kind: Option>, +) -> Option { + match binding_kind.clone().as_deref().cloned() { + Some(VarBindingKind::VariantValueBinding { parent_enum, .. }) => Some(parent_enum.clone()), _ => std::option::Option::None, } } @@ -22872,112 +22963,128 @@ pub fn emit_var_ref( { crate::v1_compiler_emit::emit_keyword(leaf_name.clone(), RenderTarget::Rust) } else { + if (rust_native_variant_spelling_of_binding( + binding_kind.clone(), + leaf_name.clone(), + ) != std::option::Option::None) { - let moves_by_value = - v1_rt::set_contains(&emit_info.movable.clone(), resolved_name.clone()); - let sharing = - crate::v1_compiler_emit_core_support::language_spec(RenderTarget::Rust) - .sharing - .clone(); - let ref_str = match variant_parent.clone() { - Some(enum_name) => { - let body = if freemonoid_empty_from_variant_parent( - leaf_name.clone(), - enum_name.clone(), - ) { - emit_freemonoid_empty_variant_body() - } else { - if (is_optional_variant_name(leaf_name.clone()) - && is_optional_like_parent_name(enum_name.clone())) - { - rust_optional_variant_spelling(leaf_name.clone()) + match rust_native_variant_spelling_of_binding( + binding_kind.clone(), + leaf_name.clone(), + ) { + Some(s) => s.clone(), + std::option::Option::None => "".to_string(), + } + } else { + { + let moves_by_value = + v1_rt::set_contains(&emit_info.movable.clone(), resolved_name.clone()); + let sharing = + crate::v1_compiler_emit_core_support::language_spec(RenderTarget::Rust) + .sharing + .clone(); + let ref_str = match variant_parent.clone() { + Some(enum_name) => { + let body = if freemonoid_empty_from_variant_parent( + leaf_name.clone(), + enum_name.clone(), + ) { + emit_freemonoid_empty_variant_body() } else { - rust_variant_path(enum_name.clone(), leaf_name.clone()) + if (is_optional_variant_name(leaf_name.clone()) + && is_optional_like_parent_name(enum_name.clone())) + { + rust_optional_variant_spelling(leaf_name.clone()) + } else { + rust_variant_path(enum_name.clone(), leaf_name.clone()) + } + }; + if variant_ref_self_wraps( + leaf_name.clone(), + enum_name.clone(), + shared_types.clone(), + ) { + rust_shared_wrap_ctor(body.clone()) + } else { + body.clone() } - }; - if variant_ref_self_wraps( - leaf_name.clone(), - enum_name.clone(), - shared_types.clone(), - ) { - rust_shared_wrap_ctor(body.clone()) - } else { - body.clone() } - } - std::option::Option::None => match (*lookup_item_for_value_ref( - resolved_name.clone(), - module_name.clone(), - registry.clone(), - emit_info.clone(), - )) - .clone() - { - ItemLookup::ItemLeafAmbiguous { - leaf: ambiguous_leaf, - .. - } => ambiguous_leaf_refusal(ambiguous_leaf.clone()), - ItemLookup::ItemFound { info: info, .. } => { - let is_data = (info.kind.clone() == ItemKind::DataItem); - if is_data.clone() { - v1_rt::concat( - emit_value_ref_ident( - name.clone(), - module_name.clone(), - registry.clone(), - emit_info.clone(), - ), - "()".to_string(), - ) - } else { - { - let is_function_value = - match binding_kind.clone().as_deref().cloned() { - Some(VarBindingKind::FunctionValueBinding) => true, - _ => false, - }; - let ident = emit_value_ref_ident( - resolved_name.clone(), - module_name.clone(), - registry.clone(), - emit_info.clone(), - ); - let ident_str = if is_function_value.clone() { - ident.clone() - } else { - if moves_by_value.clone() { + std::option::Option::None => match (*lookup_item_for_value_ref( + resolved_name.clone(), + module_name.clone(), + registry.clone(), + emit_info.clone(), + )) + .clone() + { + ItemLookup::ItemLeafAmbiguous { + leaf: ambiguous_leaf, + .. + } => ambiguous_leaf_refusal(ambiguous_leaf.clone()), + ItemLookup::ItemFound { info: info, .. } => { + let is_data = (info.kind.clone() == ItemKind::DataItem); + if is_data.clone() { + v1_rt::concat( + emit_value_ref_ident( + name.clone(), + module_name.clone(), + registry.clone(), + emit_info.clone(), + ), + "()".to_string(), + ) + } else { + { + let is_function_value = + match binding_kind.clone().as_deref().cloned() { + Some(VarBindingKind::FunctionValueBinding) => { + true + } + _ => false, + }; + let ident = emit_value_ref_ident( + resolved_name.clone(), + module_name.clone(), + registry.clone(), + emit_info.clone(), + ); + let ident_str = if is_function_value.clone() { ident.clone() } else { - match resolved_type.clone() { + if moves_by_value.clone() { + ident.clone() + } else { + match resolved_type.clone() { Some(_) => crate::v1_compiler_emit_core_support::apply_type_template1(sharing.clone_value.clone(), ident.clone()), _ => ident.clone(), } - } - }; - ident_str.clone() + } + }; + ident_str.clone() + } } } - } - ItemLookup::ItemNotFound => { - let ident = emit_value_ref_ident( - resolved_name.clone(), - module_name.clone(), - registry.clone(), - emit_info.clone(), - ); - let ident_str = if moves_by_value.clone() { - ident.clone() - } else { - match resolved_type.clone() { + ItemLookup::ItemNotFound => { + let ident = emit_value_ref_ident( + resolved_name.clone(), + module_name.clone(), + registry.clone(), + emit_info.clone(), + ); + let ident_str = if moves_by_value.clone() { + ident.clone() + } else { + match resolved_type.clone() { Some(_) => crate::v1_compiler_emit_core_support::apply_type_template1(sharing.clone_value.clone(), ident.clone()), _ => ident.clone(), } - }; - ident_str.clone() - } - }, - }; - ref_str + }; + ident_str.clone() + } + }, + }; + ref_str + } } } } @@ -23019,80 +23126,91 @@ pub fn emit_typed_expr_base( { crate::v1_compiler_emit::emit_keyword(leaf_name.clone(), RenderTarget::Rust) } else { - match variant_parent.clone() { - Some(enum_name) => { - if freemonoid_empty_from_variant_parent( - leaf_name.clone(), - enum_name.clone(), - ) { - emit_freemonoid_empty_rc_value() - } else { - { - let qualified = - if (is_optional_variant_name(leaf_name.clone()) - && is_optional_like_parent_name(enum_name.clone())) + match rust_native_variant_spelling_of_binding( + binding_kind.clone(), + leaf_name.clone(), + ) { + Some(native) => native.clone(), + std::option::Option::None => match variant_parent.clone() { + Some(enum_name) => { + if freemonoid_empty_from_variant_parent( + leaf_name.clone(), + enum_name.clone(), + ) { + emit_freemonoid_empty_rc_value() + } else { + { + let qualified = + if (is_optional_variant_name(leaf_name.clone()) + && is_optional_like_parent_name( + enum_name.clone(), + )) + { + rust_optional_variant_spelling( + leaf_name.clone(), + ) + } else { + rust_variant_path( + enum_name.clone(), + leaf_name.clone(), + ) + }; + if v1_rt::set_contains(&shared_types, enum_name.clone()) { - rust_optional_variant_spelling(leaf_name.clone()) + rust_shared_wrap_ctor(qualified.clone()) } else { - rust_variant_path( - enum_name.clone(), - leaf_name.clone(), - ) - }; - if v1_rt::set_contains(&shared_types, enum_name.clone()) { - rust_shared_wrap_ctor(qualified.clone()) - } else { - qualified.clone() + qualified.clone() + } } } } - } - std::option::Option::None => { - let resolved_name = value_ref_normalize_self_module( - n.clone(), - scope.module_name.clone(), - ); - match (*lookup_item_for_value_ref( - resolved_name.clone(), - scope.module_name.clone(), - registry.clone(), - emit_info.clone(), - )) - .clone() - { - ItemLookup::ItemLeafAmbiguous { - leaf: ambiguous_leaf, - .. - } => ambiguous_leaf_refusal(ambiguous_leaf.clone()), - ItemLookup::ItemFound { info: info, .. } => { - let is_data = (info.kind.clone() == ItemKind::DataItem); - if is_data.clone() { - v1_rt::concat( + std::option::Option::None => { + let resolved_name = value_ref_normalize_self_module( + n.clone(), + scope.module_name.clone(), + ); + match (*lookup_item_for_value_ref( + resolved_name.clone(), + scope.module_name.clone(), + registry.clone(), + emit_info.clone(), + )) + .clone() + { + ItemLookup::ItemLeafAmbiguous { + leaf: ambiguous_leaf, + .. + } => ambiguous_leaf_refusal(ambiguous_leaf.clone()), + ItemLookup::ItemFound { info: info, .. } => { + let is_data = (info.kind.clone() == ItemKind::DataItem); + if is_data.clone() { + v1_rt::concat( + emit_value_ref_ident( + n.clone(), + scope.module_name.clone(), + registry.clone(), + emit_info.clone(), + ), + "()".to_string(), + ) + } else { emit_value_ref_ident( - n.clone(), + resolved_name.clone(), scope.module_name.clone(), registry.clone(), emit_info.clone(), - ), - "()".to_string(), - ) - } else { - emit_value_ref_ident( - resolved_name.clone(), - scope.module_name.clone(), - registry.clone(), - emit_info.clone(), - ) + ) + } } + ItemLookup::ItemNotFound => emit_value_ref_ident( + resolved_name.clone(), + scope.module_name.clone(), + registry.clone(), + emit_info.clone(), + ), } - ItemLookup::ItemNotFound => emit_value_ref_ident( - resolved_name.clone(), - scope.module_name.clone(), - registry.clone(), - emit_info.clone(), - ), } - } + }, } } } diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 0989da31d00..96fe419b39a 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -52,6 +52,11 @@ pub use crate::std_induction::{InductiveField, RecursionShape, SubValueRelation} use crate::std_interface_summary::ExportKind::{ExportData, ExportFn, ExportService, ExportType}; pub use crate::std_interface_summary::{interface_summary_rollup, signature_contract}; pub use crate::std_interface_summary::{ExportEntry, ExportKind, InterfaceSummary}; +pub use crate::std_kernel_type_name::kernel_type_name; +pub use crate::std_kernel_type_name::KernelTypeNameAdmission; +use crate::std_kernel_type_name::KernelTypeNameAdmission::{ + KernelTypeNameAdmitted, NotAKernelTypeName, +}; use crate::std_literal_elaboration::LiteralElaborationOutcome::{ DirectLiteral, LiteralElaborationRefused, ViaHomomorphism, }; @@ -74,6 +79,13 @@ use crate::std_syntax::BinOp::{ use crate::std_syntax::LiteralValue::LitStr; use crate::std_syntax::LiteralValue::{LitBool, LitFloat, LitInt, LitNull}; pub use crate::std_syntax::{BinOp, LiteralValue}; +use crate::std_target_representation::VariantParentIdentity::{ + VariantParentIdentified, VariantParentUnrecovered, +}; +use crate::std_target_representation::VariantParentKey::{ + VariantParentDeclaration, VariantParentKernelType, +}; +pub use crate::std_target_representation::{VariantParentIdentity, VariantParentKey}; pub use crate::std_termination::PositiveDescentAmount; use crate::std_termination::PositiveDescentAmount::OneStep; pub use crate::std_termination::{ @@ -288,7 +300,7 @@ pub use crate::v1_std_core::{ admit_callers_entry_coords, admit_callers_entry_uninterpretable_spans, arg_name_at, arg_value, arm_body, arm_guard, arm_pattern, authored_name_at, binop_left, binop_right, bool_type, build_newline_index, call_semantics_target, callable_identity, cast_expr, cast_target, - container_expected_arity, decl_ref_coords_label, default_ident_span, + container_expected_arity, decl_ref_coords_label, declaration_provenance_of, default_ident_span, diagnostic_frontier_occurrence_key, diagnostic_to_span, empty_intern_table, error_type, expr_call_func_at, expr_has_non_tail_self_call, expr_has_self_call, expr_literal_int_optional, expr_literal_string_optional, expr_method_name_at, expr_var_name_at, field_access_base, @@ -1137,6 +1149,39 @@ pub fn variant_reference_inferred_node( } } +pub fn variant_parent_identity_of( + owner: Option>, + scope: Rc, +) -> Rc { + match owner.clone() { + std::option::Option::None => Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "no owning coproduct declaration was found for the variant".to_string(), +}), + Some(o) => match crate::v1_compiler_infer_env::type_reference_declaration(o.clone(), scope.type_env.clone().source_indices.clone(), scope.type_env.clone()) { + Some(od) => Rc::new(VariantParentIdentity::VariantParentIdentified { + key: Rc::new(VariantParentKey::VariantParentDeclaration { + declaration: od.declaration.clone(), +}), +}), + std::option::Option::None => match (*crate::v1_std_core::declaration_provenance_of(o.clone())).clone() { + TypeDeclarationProvenance::KernelMinted { minted_name: m, .. } => match (*crate::std_kernel_type_name::kernel_type_name(m.clone())).clone() { + KernelTypeNameAdmission::KernelTypeNameAdmitted { kernel_name: k, .. } => Rc::new(VariantParentIdentity::VariantParentIdentified { + key: Rc::new(VariantParentKey::VariantParentKernelType { + kernel_name: k.clone(), +}), +}), + KernelTypeNameAdmission::NotAKernelTypeName { name: _, .. } => Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "the owning coproduct is a kernel mint whose name is not a kernel type".to_string(), +}), +}, + _ => Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "the owning coproduct is neither an identified corpus declaration nor a kernel type (alias or unresolved)".to_string(), +}), +}, +}, +} +} + pub fn expected_decided_variant_value( texpr: Rc, name: String, @@ -1156,6 +1201,10 @@ pub fn expected_decided_variant_value( Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: decided_name.clone(), + parent_identity: variant_parent_identity_of( + Some(decided.clone()), + scope.clone(), + ), })), }), Rc::new(vec![]), @@ -1476,6 +1525,10 @@ pub fn infer_var_binding_kind(scope: Rc, name: String) -> Rc Rc::new(VarBindingKind::VariantValueBinding { parent_enum: parent_enum.clone(), + parent_identity: variant_parent_identity_of( + variant_owner_node(scope.clone(), name.clone()), + scope.clone(), + ), }), std::option::Option::None => match v1_rt::map_get(&scope.locals.clone(), name.clone()) { Some(binding) => { @@ -10122,6 +10175,12 @@ pub fn resolve_pattern_subject( } } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct PatternParentReading { + pub parent_enum: Option, + pub identity: Rc, +} + pub fn annotate_pattern_parent_enums( pattern: Rc, scrutinee_subject: Rc, @@ -10137,7 +10196,7 @@ pub fn annotate_pattern_parent_enums( } => { let resolved_scrut = resolve_pattern_subject(scope.clone(), scrutinee_subject.clone()); - let inferred_parent = match (*resolved_scrut.clone()).clone() { + let parent_reading = match (*resolved_scrut.clone()).clone() { PatternSubject::PatternResolved { node: resolved_scrut_node, .. @@ -10163,26 +10222,61 @@ pub fn annotate_pattern_parent_enums( && ((variant_name.clone() == "Present".to_string()) || (variant_name.clone() == "Absent".to_string()))) { - Some("Optional".to_string()) + Rc::new(PatternParentReading { + parent_enum: Some("Optional".to_string()), + identity: Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "the arm belongs to the optional wrapper, not to the scrutinee's declared coproduct".to_string(), +}), +}) } else { if witness_container_subject.clone() { - Some("Witness".to_string()) + Rc::new(PatternParentReading { + parent_enum: Some("Witness".to_string()), + identity: Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "the arm belongs to the witness wrapper, not to the scrutinee's declared coproduct".to_string(), +}), +}) } else { { let is_coproduct = (resolved_scrut_node.connective.clone() == Connective::Disj); if is_coproduct.clone() { - Some(scrutinee_name.clone()) + Rc::new(PatternParentReading { + parent_enum: Some(scrutinee_name.clone()), + identity: variant_parent_identity_of( + Some(resolved_scrut_node.clone()), + scope.clone(), + ), + }) } else { - std::option::Option::None + Rc::new(PatternParentReading { + parent_enum: std::option::Option::None, + identity: Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "the scrutinee's resolved type is not a coproduct declaration".to_string(), +}), +}) } } } } } - PatternSubject::PatternDynamic { span: _, .. } => std::option::Option::None, - PatternSubject::PatternLookupBlocked => std::option::Option::None, + PatternSubject::PatternDynamic { span: _, .. } => { + Rc::new(PatternParentReading { + parent_enum: std::option::Option::None, + identity: Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "the scrutinee's type is dynamic".to_string(), + }), + }) + } + PatternSubject::PatternLookupBlocked => Rc::new(PatternParentReading { + parent_enum: std::option::Option::None, + identity: Rc::new(VariantParentIdentity::VariantParentUnrecovered { + cause: "the scrutinee's type lookup was blocked".to_string(), + }), + }), }; + let inferred_parent = parent_reading.parent_enum.clone(); + let parent_identity = parent_reading.identity.clone(); let annotated_variant_name = variant_name.clone(); let variant_lookup = crate::v1_compiler_infer_patterns::lookup_variant_in_type( resolved_scrut.clone(), @@ -10237,11 +10331,13 @@ pub fn annotate_pattern_parent_enums( name: annotated_variant_name.clone(), parent_enum: Some(parent_name.clone()), field_bindings: annotated_bindings.clone(), + parent_identity: parent_identity.clone(), }), std::option::Option::None => Rc::new(MatchPattern::VariantPattern { name: variant_name.clone(), parent_enum: std::option::Option::None, field_bindings: annotated_bindings.clone(), + parent_identity: parent_identity.clone(), }), } } @@ -11538,6 +11634,7 @@ pub fn unfold_peano_image( succ: String, prev_field: String, parent: String, + parent_identity: Rc, destination_type: Rc, span: Rc, ) -> Rc { @@ -11548,6 +11645,7 @@ pub fn unfold_peano_image( Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: parent.clone(), + parent_identity: parent_identity.clone(), })), }), Rc::new(vec![]), @@ -11562,6 +11660,7 @@ pub fn unfold_peano_image( succ.clone(), prev_field.clone(), parent.clone(), + parent_identity.clone(), destination_type.clone(), span.clone(), ); @@ -11632,7 +11731,11 @@ pub fn unfold_literal_image( _ => crate::v1_std_core::make_expr_error_node(Rc::new(NodeOccurrenceIdentity::OccurrenceSynthetic), ExprErrorKind::InternalExprError, "literal elaboration: a Unicode-scalar-sequence unfolding row was selected for a non-string literal (gunbc.structural_realization_bindings keys the row on KernelStringLiteral, so this row is malformed)".to_string(), span.clone()), }, LiteralUnfolding::PeanoUnfold { zero, succ, prev_field, .. } => match (*lit.clone()).clone() { - LiteralValue::LitInt { value: n, .. } => unfold_peano_image(n.clone(), zero.decl_name.clone(), succ.decl_name.clone(), prev_field.clone(), elaboration.destination.clone().decl_name.clone(), destination_type.clone(), span.clone()), + LiteralValue::LitInt { value: n, .. } => unfold_peano_image(n.clone(), zero.decl_name.clone(), succ.decl_name.clone(), prev_field.clone(), elaboration.destination.clone().decl_name.clone(), Rc::new(VariantParentIdentity::VariantParentIdentified { + key: Rc::new(VariantParentKey::VariantParentDeclaration { + declaration: elaboration.destination.clone(), +}), +}), destination_type.clone(), span.clone()), _ => crate::v1_std_core::make_expr_error_node(Rc::new(NodeOccurrenceIdentity::OccurrenceSynthetic), ExprErrorKind::InternalExprError, "literal elaboration: a Peano unfolding row was selected for a non-integer literal (gunbc.structural_realization_bindings keys the row on KernelIntLiteral, so this row is malformed)".to_string(), span.clone()), }, LiteralUnfolding::BooleanUnfold { true_variant: t, false_variant: f, .. } => match (*lit.clone()).clone() { @@ -11643,6 +11746,11 @@ pub fn unfold_literal_image( }, Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: elaboration.destination.clone().decl_name.clone(), + parent_identity: Rc::new(VariantParentIdentity::VariantParentIdentified { + key: Rc::new(VariantParentKey::VariantParentDeclaration { + declaration: elaboration.destination.clone(), +}), +}), })), }), Rc::new(vec![]), destination_type.clone(), span.clone()), _ => crate::v1_std_core::make_expr_error_node(Rc::new(NodeOccurrenceIdentity::OccurrenceSynthetic), ExprErrorKind::InternalExprError, "literal elaboration: a Boolean unfolding row was selected for a non-boolean literal (gunbc.structural_realization_bindings keys the row on KernelBoolLiteral, so this row is malformed)".to_string(), span.clone()), @@ -11883,6 +11991,7 @@ match scope_parent.clone() { typed: crate::v1_std_core::make_named_expr_node(texpr.occurrence_identity.clone(), name.clone(), Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: scope_enum.clone(), + parent_identity: variant_parent_identity_of(variant_owner_node(scope.clone(), name.clone()), scope.clone()), })), }), Rc::new(vec![]), Some(Rc::new(InferredNode::Resolved { node: variant_reference_inferred_node(expected.clone(), name.clone(), scope_enum.clone(), scope.clone(), binding.resolved.clone()), @@ -11938,6 +12047,7 @@ match scope_parent.clone() { typed: crate::v1_std_core::make_named_expr_node(texpr.occurrence_identity.clone(), name.clone(), Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: scope_enum.clone(), + parent_identity: variant_parent_identity_of(variant_owner_node(scope.clone(), name.clone()), scope.clone()), })), }), Rc::new(vec![]), Some(Rc::new(InferredNode::Resolved { node: variant_reference_inferred_node(expected.clone(), name.clone(), scope_enum.clone(), scope.clone(), gbinding.resolved.clone()), @@ -11949,6 +12059,7 @@ match scope_parent.clone() { typed: crate::v1_std_core::make_named_expr_node(texpr.occurrence_identity.clone(), name.clone(), Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: crate::v1_std_core::authored_name_at(scope.type_env.clone().source_indices.clone(), exp_enum.clone()), + parent_identity: variant_parent_identity_of(Some(exp_enum.clone()), scope.clone()), })), }), Rc::new(vec![]), Some(Rc::new(InferredNode::Resolved { node: exp_enum.clone(), @@ -11994,6 +12105,7 @@ match expected_variant_enum.clone() { typed: crate::v1_std_core::make_named_expr_node(texpr.occurrence_identity.clone(), name.clone(), Rc::new(ExprData::ExprVar { binding_kind: Some(Rc::new(VarBindingKind::VariantValueBinding { parent_enum: crate::v1_std_core::authored_name_at(scope.type_env.clone().source_indices.clone(), exp_enum.clone()), + parent_identity: variant_parent_identity_of(Some(exp_enum.clone()), scope.clone()), })), }), Rc::new(vec![]), Some(Rc::new(InferredNode::Resolved { node: exp_enum.clone(), diff --git a/src/v1/stage0/src/v1_compiler_parse.rs b/src/v1/stage0/src/v1_compiler_parse.rs index 14e1b9bee26..07cb54514ae 100644 --- a/src/v1/stage0/src/v1_compiler_parse.rs +++ b/src/v1/stage0/src/v1_compiler_parse.rs @@ -51,6 +51,8 @@ pub use crate::std_syntax::{ BinOp, BodyKind, ItemForm, ItemFormKind, LiteralValue, OperatorSpec, ParseEnvironment, SyntaxSpec, }; +pub use crate::std_target_representation::VariantParentIdentity; +use crate::std_target_representation::VariantParentIdentity::VariantParentBeforeInference; pub use crate::std_types::{NonEmptyStr, SourceSpan}; use crate::v1_rt; use crate::v1_rt::{VecCompat, VecJoin}; @@ -3048,6 +3050,7 @@ pub fn stamp_parsed_pattern( name, parent_enum, field_bindings, + parent_identity, .. }) => { let stamped = stamp_parsed_node_list( @@ -3063,6 +3066,7 @@ pub fn stamp_parsed_pattern( name: name.clone(), parent_enum: parent_enum.clone(), field_bindings: stamped.nodes.clone(), + parent_identity: parent_identity.clone(), })), ctx: stamped.ctx.clone(), err: stamped.err.clone(), @@ -16428,6 +16432,9 @@ pub fn parse_variant_pattern( name: name.clone(), parent_enum: std::option::Option::None, field_bindings: r.field_bindings.clone(), + parent_identity: Rc::new( + VariantParentIdentity::VariantParentBeforeInference, + ), }), tokens: r2.tokens.clone(), ctx: r.ctx.clone(), @@ -16468,6 +16475,9 @@ pub fn parse_variant_pattern( name: name.clone(), parent_enum: std::option::Option::None, field_bindings: Rc::new(vec![fb.clone()]), + parent_identity: Rc::new( + VariantParentIdentity::VariantParentBeforeInference, + ), }), tokens: r2.tokens.clone(), ctx: minted.ctx.clone(), @@ -16480,6 +16490,9 @@ pub fn parse_variant_pattern( name: name.clone(), parent_enum: std::option::Option::None, field_bindings: Rc::new(vec![]), + parent_identity: Rc::new( + VariantParentIdentity::VariantParentBeforeInference, + ), }), tokens: tokens.clone(), ctx: ctx.clone(), diff --git a/src/v1/stage0/src/v1_interpreter.rs b/src/v1/stage0/src/v1_interpreter.rs index 693339e818b..da09a84f05f 100644 --- a/src/v1/stage0/src/v1_interpreter.rs +++ b/src/v1/stage0/src/v1_interpreter.rs @@ -1258,6 +1258,14 @@ pub enum InterpError { at: String, found: String, }, + /// A variant occurrence of a natively realized coproduct (std.types Bool over the host `bool`) + /// whose realization could not be decided -- its owning coproduct was not recovered, or the + /// row set refused -- so it is refused rather than matched or constructed by its arm NAME. + /// The decision is `v1.compiler.coercion` `rust_variant_value_realization`, the same one the + /// Rust emitter consumes. + VariantRealizationRefused { + detail: String, + }, /// A REST response value did not inhabit the coproduct its declared output type names. /// Raised by `decode_json_by_declared_type`; see `RestResponseDecodeRefusal`. RestResponseUndecodable { @@ -1496,6 +1504,9 @@ impl fmt::Display for InterpError { InterpError::StringRealizationStraddle { detail } => { write!(f, "string realization straddle: {}", detail) } + InterpError::VariantRealizationRefused { detail } => { + write!(f, "{}", detail) + } InterpError::PoolRootContributesNothing { caller, declared, @@ -5306,6 +5317,11 @@ pub struct InterpContext { // eval goes straight to env.lookup(sym), materializing the String only on the registry slow path. var_sym_cache: std::cell::RefCell>, var_sym_cache_keepalive: std::cell::RefCell>>, + /// A refusal raised inside `match_pattern` (which answers match / no-match as an `Option`), + /// taken by the one caller that owns the match and turned into + /// `InterpError::VariantRealizationRefused` -- so an undecidable native arm stops the match + /// instead of falling through to the next arm. + variant_realization_refusal: std::cell::RefCell>, // Same chokepoint, ExprCall callee name: eval_call re-sliced the callee name from its source // span (expr_call_func_at -> authored_name_at) on every call. Memoize the decoded name per // call node — keyed by node pointer, kept alive via call_func_name_cache_keepalive as above. @@ -5739,6 +5755,7 @@ impl InterpContext { param_name_cache_keepalive: std::cell::RefCell::new(Vec::new()), var_sym_cache: std::cell::RefCell::new(HashMap::new()), var_sym_cache_keepalive: std::cell::RefCell::new(Vec::new()), + variant_realization_refusal: std::cell::RefCell::new(None), call_func_name_cache: std::cell::RefCell::new(HashMap::new()), call_func_name_cache_keepalive: std::cell::RefCell::new(Vec::new()), cast_kernel_cache: std::cell::RefCell::new(HashMap::new()), @@ -7098,7 +7115,25 @@ fn eval_var( } }; - if let Some(VarBindingKind::VariantValueBinding { parent_enum }) = binding_kind { + if let Some(VarBindingKind::VariantValueBinding { + parent_enum, + parent_identity, + }) = binding_kind + { + let arm_spelling = ctx.resolve(sym); + let arm = arm_spelling.rsplit('.').next().unwrap_or(&arm_spelling); + match native_variant_reading(parent_identity, arm) { + NativeVariantReading::HostBool(b) => return Ok(Value::Bool(b)), + NativeVariantReading::Structural => {} + NativeVariantReading::Refused(detail) => { + // A value construction refuses only for an arm a native row could have claimed; + // an unrecovered owner whose arm no row mentions is structural, as in emission. + if crate::v1_compiler_coercion::rust_variant_arm_is_bound_somewhere(arm.to_string()) + { + return Err(InterpError::VariantRealizationRefused { detail }); + } + } + } // Bounded residual: Nat's intentional native representation is still selected by the // arm lexeme because the seed binding carrier lacks exact owner declaration identity. // The executable shorthand test and GuaranteeStall keep that silent-wrongness path @@ -7915,7 +7950,11 @@ fn eval_match(node: &Rc, env: &Rc, ctx: &InterpContext) -> InterpResu } else { scrutinee_val.clone() }; - if let Some(bindings) = match_pattern(&pattern, &arm_value, ctx) { + let matched = match_pattern(&pattern, &arm_value, ctx); + if let Some(detail) = ctx.variant_realization_refusal.borrow_mut().take() { + return Err(InterpError::VariantRealizationRefused { detail }); + } + if let Some(bindings) = matched { let arm_env = Env::extend(env, bindings); // A guard is part of the arm's admission, evaluated in the arm's bindings: a false // guard falls through to the next arm, exactly as the emitted `pat if guard =>` does. @@ -8991,6 +9030,41 @@ fn try_witness_evaluation_dispatch( } } +/// THE INTERPRETER'S HALF OF THE NATIVE-VARIANT LOWERING. The interpreter is a Rust-hosted +/// realization whose `Value::Bool` holds a Rust `bool`, so it asks the SAME identity-keyed decision +/// the Rust emitter asks (`v1.compiler.coercion` `rust_variant_value_realization`, over +/// `gunbc.rust_source_type_bindings` `rust_source_variant_value_rows`) and reads the row's value +/// with Rust's own `bool` parse -- the projection of that row onto this host, not a second table. +enum NativeVariantReading { + HostBool(bool), + Structural, + Refused(String), +} + +fn native_variant_reading( + parent: &Rc, + arm: &str, +) -> NativeVariantReading { + use crate::std_target_representation::VariantValueRealization as R; + let r = crate::v1_compiler_coercion::rust_variant_value_realization( + parent.clone(), + arm.to_string(), + ); + match &*r { + R::VariantRealizesAsTargetValue { value_spelling } => match value_spelling.parse::() { + Ok(b) => NativeVariantReading::HostBool(b), + Err(_) => NativeVariantReading::Refused(format!( + "variant realization: arm `{arm}` realizes as the target value `{value_spelling}`, which the interpreter's host bool cannot hold" + )), + }, + R::VariantRealizesStructurally => NativeVariantReading::Structural, + _ => NativeVariantReading::Refused( + crate::std_target_representation::variant_value_realization_refusal_message(r.clone()) + .unwrap_or_else(|| format!("variant realization: arm `{arm}` was refused")), + ), + } +} + fn match_pattern( pattern: &MatchPattern, value: &Value, @@ -9019,7 +9093,29 @@ fn match_pattern( name, parent_enum, field_bindings, + parent_identity, } => { + // A variant pattern against a HOST bool is a native arm or nothing: the identity + // inference carried decides which value it denotes, and an undecidable one refuses. + // Variant values (a module-local coproduct whose arms happen to be spelled True/False) + // never reach this branch and keep their structural match below. + if let Value::Bool(held) = value { + let arm = name.rsplit('.').next().unwrap_or(name); + return match native_variant_reading(parent_identity, arm) { + NativeVariantReading::HostBool(b) => { + if *held == b { + Some(HashMap::new()) + } else { + None + } + } + NativeVariantReading::Structural => None, + NativeVariantReading::Refused(detail) => { + *ctx.variant_realization_refusal.borrow_mut() = Some(detail); + None + } + }; + } // A qualified pattern spelling (`module.Variant`) resolves the arm name to its // containment path, but values are constructed with the bare last segment (the // short-name normalization at value construction). Every name-vs-literal diff --git a/src/v1/stage0/src/v1_std_core.rs b/src/v1/stage0/src/v1_std_core.rs index 15858fd71ca..90cd7e699c1 100644 --- a/src/v1/stage0/src/v1_std_core.rs +++ b/src/v1/stage0/src/v1_std_core.rs @@ -81,6 +81,8 @@ use crate::std_syntax::BinOp::{ }; use crate::std_syntax::LiteralValue::{LitBool, LitFloat, LitInt, LitNull, LitStr, LitSymbol}; pub use crate::std_syntax::{AlgebraFieldKind, BinOp, LiteralValue}; +pub use crate::std_target_representation::VariantParentIdentity; +use crate::std_target_representation::VariantParentIdentity::*; pub use crate::std_types::{ container_expected_arity, container_type_arity, is_container_type, is_kernel_type, kernel_type_set, @@ -267,7 +269,10 @@ pub fn has_inferred(n: Rc) -> bool { pub enum VarBindingKind { LocalValueBinding, FunctionValueBinding, - VariantValueBinding { parent_enum: String }, + VariantValueBinding { + parent_enum: String, + parent_identity: Rc, + }, MatchBoundBinding, ServiceValueBinding, } @@ -283,6 +288,18 @@ impl VarBindingKind { VarBindingKind::ServiceValueBinding => panic!("no parent_enum on unit variant"), } } + pub fn parent_identity(&self) -> Rc { + match self { + VarBindingKind::LocalValueBinding => panic!("no parent_identity on unit variant"), + VarBindingKind::FunctionValueBinding => panic!("no parent_identity on unit variant"), + VarBindingKind::VariantValueBinding { + parent_identity: __val, + .. + } => __val.clone(), + VarBindingKind::MatchBoundBinding => panic!("no parent_identity on unit variant"), + VarBindingKind::ServiceValueBinding => panic!("no parent_identity on unit variant"), + } + } } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] @@ -477,6 +494,7 @@ pub enum MatchPattern { name: String, parent_enum: Option, field_bindings: Rc>>, + parent_identity: Rc, }, Wildcard, } diff --git a/src/v1/stage0_std_core/src/lib.rs b/src/v1/stage0_std_core/src/lib.rs index 6c88ffb6cb3..7215994dca7 100644 --- a/src/v1/stage0_std_core/src/lib.rs +++ b/src/v1/stage0_std_core/src/lib.rs @@ -132,6 +132,9 @@ pub mod std_occurrence_identity; #[path = "../../stage0/src/std_source_annotation.rs"] pub mod std_source_annotation; #[rustfmt::skip] +#[path = "../../stage0/src/std_kernel_type_name.rs"] +pub mod std_kernel_type_name; +#[rustfmt::skip] #[path = "../../stage0/src/std_target_representation.rs"] pub mod std_target_representation; #[rustfmt::skip] diff --git a/src/v2/test/claim/logic/native_bool_arm_interpretation_test.dag b/src/v2/test/claim/logic/native_bool_arm_interpretation_test.dag new file mode 100644 index 00000000000..222e7a8f79f --- /dev/null +++ b/src/v2/test/claim/logic/native_bool_arm_interpretation_test.dag @@ -0,0 +1,30 @@ +module v2.test.claim.logic.native_bool_arm_interpretation_test + +import v2.test.fixture.local_verdict_coproduct { verdict_top, verdict_negate, verdict_is_top } + +// THE INTERPRETER'S HALF OF THE NATIVE-VARIANT LOWERING, through the real interpreter route. The +// arms of std.types Bool (the kernel Bool every module's `Bool` resolves to) realize as the host +// bool: a `True`/`False` pattern matches the host values and a constructed `True` IS host true. +// Before the lowering the interpreter matched variant patterns by name against a host bool and +// failed (PatternMatchFailure { value: "true" }). +// +// The patterns are the subject here, so the arm bodies return host values. A bare `True`/`False` +// VALUE in this corpus still resolves to v2.std.logic's structural Bool until the Bool de-fork +// deletes it; the constructed-arm claim therefore lives with that cut, where the one Bool is the +// only thing a bare arm can mean. +fn negate_by_arms(b: Bool) -> Bool { + match b { + True => false + False => true + } +} + +test fn bool_arms_match_the_host_values() -> Bool { + negate_by_arms(b: true) == false && negate_by_arms(b: false) == true +} + +// THE IDENTITY CONTROL: a module-local coproduct whose arms are spelled True/False keeps being its +// own coproduct in the interpreter -- constructed as its variant, matched as its variant. +test fn a_local_coproduct_with_true_false_arms_stays_its_own_variants() -> Bool { + verdict_is_top(v: verdict_top()) && !verdict_is_top(v: verdict_negate(v: verdict_top())) +} diff --git a/src/v2/test/fixture/local_verdict_coproduct.dag b/src/v2/test/fixture/local_verdict_coproduct.dag new file mode 100644 index 00000000000..f7829349423 --- /dev/null +++ b/src/v2/test/fixture/local_verdict_coproduct.dag @@ -0,0 +1,25 @@ +module v2.test.fixture.local_verdict_coproduct + +// A MODULE-LOCAL COPRODUCT WHOSE ARMS ARE SPELLED True/False, for the identity control in +// v2.test.claim.logic.native_bool_arm_interpretation_test. It has no row in +// gunbc.rust_source_type_bindings, so the interpreter must construct and match it as its own +// variants, never as the host bool its arm spellings resemble. +type Verdict = True | False + +fn verdict_top() -> Verdict { + True +} + +fn verdict_negate(v: Verdict) -> Verdict { + match v { + True => False + False => True + } +} + +fn verdict_is_top(v: Verdict) -> Bool { + match v { + True => true + False => false + } +} diff --git a/src/v2/workflow/rust_crate_partition.dag b/src/v2/workflow/rust_crate_partition.dag index 5d6d754d667..90bce45853d 100644 --- a/src/v2/workflow/rust_crate_partition.dag +++ b/src/v2/workflow/rust_crate_partition.dag @@ -341,6 +341,7 @@ fn stage0_std_core_modules() -> List { "extdeps_units_iso_80000_3", "std_occurrence_identity", "std_source_annotation", + "std_kernel_type_name", "std_target_representation", "std_literal_elaboration", "std_operator_realization",