From 7dfac975bee58abec91da6d301dff3ffa3d09561 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 3 Oct 2026 23:38:35 +0000 Subject: [PATCH 01/69] WIP checker: refuse T? == T (EqualityOptionalityMismatch) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/00_core.dag | 5 +++++ src/v1/04_infer.dag | 23 ++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/v1/00_core.dag b/src/v1/00_core.dag index 96d70f0d61e..810e1c8d125 100644 --- a/src/v1/00_core.dag +++ b/src/v1/00_core.dag @@ -437,6 +437,7 @@ type CompilerDiagnostic | CallNamedArgOnFunctionValue { callee: String, argument: String, span: SourceSpan } | EqualityOnFunctionMember { type_name: String, member: String, span: SourceSpan } | EqualityMemberUnjudgeable { type_name: String, member: String, span: SourceSpan } + | EqualityOptionalityMismatch { optional_side: String, span: SourceSpan } | TypeArgumentArityMismatch { type_name: String, supplied: Int, declared: Int, span: SourceSpan } | TypeArgumentKindMismatch { type_name: String, param_name: String, kind_name: String, supplied: String, span: SourceSpan } | TypeParameterInValuePosition { name: String, span: SourceSpan } @@ -666,6 +667,7 @@ fn diagnostic_to_span(d: CompilerDiagnostic) -> SourceSpan { CallNamedArgOnFunctionValue { callee: _, argument: _, span: s } => s EqualityOnFunctionMember { type_name: _, member: _, span: s } => s EqualityMemberUnjudgeable { type_name: _, member: _, span: s } => s + EqualityOptionalityMismatch { optional_side: _, span: s } => s TypeArgumentArityMismatch { type_name: _, supplied: _, declared: _, span: s } => s TypeArgumentKindMismatch { type_name: _, param_name: _, kind_name: _, supplied: _, span: s } => s TypeParameterInValuePosition { name: _, span: s } => s @@ -778,6 +780,8 @@ fn diagnostic_to_message(d: CompilerDiagnostic) -> String { concat("equality is not defined for '", t, "': member '", m, "' is function-valued, and function equality has no denotation — compare a declared identity for this type instead of '=='") EqualityMemberUnjudgeable { type_name: t, member: m, span: _ } => concat("equality admission for '", t, "' cannot be judged: ", m, " — '==' is refused rather than admitted on an unjudged member") + EqualityOptionalityMismatch { optional_side: side, span: _ } => + concat("'==' compares an optional value with a required one (the ", side, " operand is optional): no declared coercion lifts T into T?, so the comparison has no single meaning -- compare against Present { value: .. } or match on the optional") TypeArgumentArityMismatch { type_name: t, supplied: s, declared: d, span: _ } => concat("type argument arity mismatch applying '", t, "': ", to_string(value: s), " type argument(s) supplied, ", to_string(value: d), " type parameter(s) declared") TypeArgumentKindMismatch { type_name: t, param_name: p, kind_name: k, supplied: sup, span: _ } => @@ -911,6 +915,7 @@ fn diagnostic_disposition(d: CompilerDiagnostic) -> DiagnosticDisposition { CallNamedArgOnFunctionValue { callee: _, argument: _, span: _ } => DiagnosticDisposition { severity: SeverityError, gate: GateBlocking } EqualityOnFunctionMember { type_name: _, member: _, span: _ } => DiagnosticDisposition { severity: SeverityError, gate: GateBlocking } EqualityMemberUnjudgeable { type_name: _, member: _, span: _ } => DiagnosticDisposition { severity: SeverityError, gate: GateBlocking } + EqualityOptionalityMismatch { optional_side: _, span: _ } => DiagnosticDisposition { severity: SeverityError, gate: GateBlocking } TypeArgumentArityMismatch { type_name: _, supplied: _, declared: _, span: _ } => DiagnosticDisposition { severity: SeverityError, gate: GateBlocking } TypeArgumentKindMismatch { type_name: _, param_name: _, kind_name: _, supplied: _, span: _ } => DiagnosticDisposition { severity: SeverityError, gate: GateBlocking } TypeParameterInValuePosition { name: _, span: _ } => DiagnosticDisposition { severity: SeverityError, gate: GateBlocking } diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 1ef8d0f0f3b..b813a9a77e3 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -56,7 +56,7 @@ import v1.std.core { Unmarked, declaration_provenance_of, FrontierOccurrenceKey, diagnostic_frontier_occurrence_key, InternalError, TypeMismatch, TypeParameterInValuePosition, TextRepresentationUnidentifiedAtBoundary, VariantCollision, SoleConstructorViolation, OptionalCastNotEliminated, BareNoneNotAdmittedByFieldType, ConstructorCallAdmissionRefused, UnresolvedType, FieldNotFound, MethodNotFound, MethodExistenceUndecided, MethodExistenceFrontierAdmitted, ReceiverTypeUnestablished, FrontierOccurrenceBudgetExceeded, MissingField, AmbiguousReference, ServiceConfigReferenceJudgmentDeferred, UnlistedVariantValueUse, CallArgumentNameUnknown, CallPositionalSurplus, CallPositionalDeficit, CallNamedArgOnFunctionValue, CallArgumentDuplicate, - EqualityOnFunctionMember, EqualityMemberUnjudgeable, + EqualityOnFunctionMember, EqualityMemberUnjudgeable, EqualityOptionalityMismatch, TypeArgumentArityMismatch, resource_use_name_at, resource_use_resource, is_child_accessor_in_model, is_tree_size_reducing, is_property_contraction, @@ -3401,6 +3401,24 @@ fn equality_operand_is_presence_literal(n: Node, source_indices: Map) -> Bool { + match n.inferred { + Present { value: Resolved { node: rt } } => + rt.return_cardinality == CardOptional + || (qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: rt)) == "Optional" && (rt.children |> count) == 1) + _ => false + } +} + fn equality_admission_refusal_diag(r: EqualityAdmissionRefusal, span: SourceSpan) -> CompilerDiagnostic { if r.member_judged { EqualityOnFunctionMember { type_name: r.type_name, member: r.member, span: span } @@ -3441,6 +3459,9 @@ fn equality_admission_diags(op: BinOp, left_typed: Node, right_typed: Node, scop || (lt.inferred != none && is_compiler_error(inferred: lt.inferred.value)) || (rt.inferred != none && is_compiler_error(inferred: rt.inferred.value)) { [] + } else if equality_operand_is_optional(n: left_typed, source_indices: source_indices) != equality_operand_is_optional(n: right_typed, source_indices: source_indices) { + let side = if equality_operand_is_optional(n: left_typed, source_indices: source_indices) { "left" } else { "right" } + [make_error_node(diagnostic: EqualityOptionalityMismatch { optional_side: side, span: span }, module_name: scope.module_name)] } else { match equality_operand_admission(n: lt, scope: scope, visited: empty_map(), depth: 0) { Present { value: r } => [make_error_node(diagnostic: equality_admission_refusal_diag(r: r, span: span), module_name: scope.module_name)] From 4197312c1b9f2238ea9cec7a5d051cacc1217611 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 00:05:19 +0000 Subject: [PATCH 02/69] C4: install regenerated seed; compile_clean census knows EqualityOptionalityMismatch Co-Authored-By: Claude Opus 5.5 (1M context) --- .../optional_compared_with_required_value.dag | 28 +++++++ ...f_host_equality_admission_witness_test.dag | 36 +++++++++ src/v1/stage0/src/cli_run/compile_clean.rs | 5 ++ src/v1/stage0/src/v1_compiler_infer.rs | 77 ++++++++++++++----- src/v1/stage0/src/v1_std_core.rs | 10 +++ 5 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag diff --git a/dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag b/dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag new file mode 100644 index 00000000000..ba933675973 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag @@ -0,0 +1,28 @@ +module gunbc.recurring_failure_mode.optional_compared_with_required_value + +import std.types { NonEmptyStr } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data optional_compared_with_required_value: RecurringFailureMode = RecurringFailureMode { + identity: "optional_compared_with_required_value" as NonEmptyStr, + + receipts: [ + "optional compared with required value: `==` or `!=` between a `T?` operand and a `T` operand (std.filesystem is_text_readable: `entry.symlink_target == TargetFile`, with symlink_target: SymlinkTarget?). No declared coercion route lifts T into T? (DESIGN section 4, operator ruling 2026-09-26: implicit coercion is only the implicit-safe subset of declared routes), so the comparison has no single meaning, yet the checker accepted it with zero diagnostics.", + + "INVALID STATE AND HARM, ONE PER REALIZATION, AND THEY DISAGREE. The interpreter answers by REPRESENTATION, not meaning: an optional held bare compares equal to the bare variant, while the same optional held as `Present { value: .. }` compares unequal. That is silent wrongness, which sits outside the ladder: one program, two answers, decided by how a value happened to be stored. The Rust emitter rendered `Option == T`, which rustc refuses (E0308), so the emission path failed loudly while the interpretation path answered silently. Measured on the approval broker's native probe (wave 2C, class C4).", + + "DISTINGUISHING FACT: the defect is at ACCEPTANCE, not at either realization. Teaching the emitter to lift (`== Some(..)`) would have legalized an undeclared conversion at the target layer -- a target's cast table is not the source language's conversion semantics -- and left the interpreter's representation-dependent answer standing. The earliest unjustified boundary (DESIGN 6b) is the checker admitting the comparison (gentle-dove-36 ruling A, 2026-10-03).", + + "WALL: v1.compiler.infer equality_admission_diags refuses Eq/Ne when exactly one operand's resolved type is optional (CardOptional on the typed operand, the fact the emitter reads, or the nominal Optional coproduct), as the blocking EqualityOptionalityMismatch. The presence idiom (`== none`, `== Absent`, `== []`) is exempt before the arm runs, as it already was for the function-member wall. Each refused corpus site was rewritten to say the meaning it intends (an explicit Present comparison or a match), never by inserting a lift.", + + "EVIDENCE: test.claim.self_host_equality_admission_witness. Reds: a `Kind?` field compared with a bare variant in both operand orders, each refused once and blocking. Controls: an explicit `== Present { value: .. }`, a match on the optional, and two optionals compared with each other, all admitted.", + + "RUNG FOUND AT: below the ladder on the interpretation path (silent, representation-dependent answer), 1 on the Rust emission path (rustc refusal).", + + "RUNG NOW: 3, structurally guaranteed, AT THE BINARY-OPERATOR SEAM: no Accepted program contains `T? == T` or `T? != T` written as a binary operator, on either realization path, because acceptance refuses it before interpretation or emission. The discriminating red and positive controls are enrolled in the witness module above. Stated at its grain: equality reached through other routes -- a generic helper whose type parameter is instantiated at T? on one side and T on the other, or a host comparison inside a primitive -- is not judged by this arm.", + + "CEILING: 4 is not attainable while the surface can spell an optional operand beside a required one. 3 is the honest ceiling for the operator form. NEXT-RUNG TRIGGER for the residual routes: instantiation-grain equality admission (the trigger equality_admission_wall_note already names), which would judge a generic `==` where its type arguments are known.", + ], + + evidence: [], +} diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 3d7f33638d8..5ec116fd70a 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -101,3 +101,39 @@ test fn structural_record_equality_stays_admitted() -> Bool { test fn presence_test_stays_admitted() -> Bool { eq_census_clean(source: presence_test_green_source) } + +// T? == T (gunbc.recurring_failure_mode optional_compared_with_required_value). Before the arm +// in v1.compiler.infer equality_admission_diags these compiled clean and the Rust emitter +// rendered `Option == T` (rustc E0308, std.filesystem is_text_readable). The red is a +// field typed `Kind?` compared with a bare variant, in both operand orders; the controls are +// the explicit spellings the refusal names (a Present comparison, a match) and two optionals +// compared with each other, which the arm must not widen into. +data optionality_mismatch_red_source: String = "module eq_probe_optionality\ntype Kind = A | B\ntype Row { kind: Kind? }\nfn is_a(r: Row) -> Bool { r.kind == A }\n" + +data optionality_mismatch_reversed_red_source: String = "module eq_probe_optionality_rev\ntype Kind = A | B\ntype Row { kind: Kind? }\nfn is_a(r: Row) -> Bool { A != r.kind }\n" + +data optionality_explicit_present_green_source: String = "module eq_probe_optionality_present\ntype Kind = A | B\ntype Row { kind: Kind? }\nfn is_a(r: Row) -> Bool { r.kind == Present { value: A } }\n" + +data optionality_explicit_match_green_source: String = "module eq_probe_optionality_match\ntype Kind = A | B\ntype Row { kind: Kind? }\nfn is_a(r: Row) -> Bool {\n match r.kind {\n Present { value: k } => k == A\n Absent => false\n }\n}\n" + +data optionality_both_optional_green_source: String = "module eq_probe_optionality_both\ntype Kind = A | B\ntype Row { kind: Kind? }\nfn same(a: Row, b: Row) -> Bool { a.kind == b.kind }\n" + +test fn optional_compared_with_required_value_refuses_blocking() -> Bool { + eq_blocking_count(source: optionality_mismatch_red_source, wanted: "EqualityOptionalityMismatch") == 1 +} + +test fn required_compared_with_optional_value_refuses_blocking() -> Bool { + eq_blocking_count(source: optionality_mismatch_reversed_red_source, wanted: "EqualityOptionalityMismatch") == 1 +} + +test fn explicit_present_comparison_stays_admitted() -> Bool { + eq_admitted(source: optionality_explicit_present_green_source) +} + +test fn explicit_match_on_optional_stays_admitted() -> Bool { + eq_admitted(source: optionality_explicit_match_green_source) +} + +test fn optional_compared_with_optional_stays_admitted() -> Bool { + eq_admitted(source: optionality_both_optional_green_source) +} diff --git a/src/v1/stage0/src/cli_run/compile_clean.rs b/src/v1/stage0/src/cli_run/compile_clean.rs index 1d8d96f6a6e..e078b92f266 100644 --- a/src/v1/stage0/src/cli_run/compile_clean.rs +++ b/src/v1/stage0/src/cli_run/compile_clean.rs @@ -1113,6 +1113,7 @@ pub fn compile_clean_diagnostic_class_specimen() -> Vec { CallNamedArgOnFunctionValue { callee: s(), argument: s(), span: no_span() }, EqualityOnFunctionMember { type_name: s(), member: s(), span: no_span() }, EqualityMemberUnjudgeable { type_name: s(), member: s(), span: no_span() }, + EqualityOptionalityMismatch { optional_side: s(), span: no_span() }, TypeArgumentArityMismatch { type_name: s(), supplied: 0, declared: 0, span: no_span() }, OccurrenceTransportViolation { refusal: Rc::new(crate::std_occurrence_identity::OccurrenceTransportRefusal::MissingAuthoredOccurrenceIdentity { diagnostic_span: no_span() }), @@ -1603,6 +1604,7 @@ pub fn compile_clean_diagnostic_histogram_key(d: &Rc) -> (String, Str CompilerDiagnostic::TypeParameterInValuePosition { .. } => "TypeParameterInValuePosition", CompilerDiagnostic::EqualityOnFunctionMember { .. } => "EqualityOnFunctionMember", CompilerDiagnostic::EqualityMemberUnjudgeable { .. } => "EqualityMemberUnjudgeable", + CompilerDiagnostic::EqualityOptionalityMismatch { .. } => "EqualityOptionalityMismatch", CompilerDiagnostic::OccurrenceTransportViolation { .. } => "OccurrenceTransportViolation", CompilerDiagnostic::SourceAnnotationRefused { .. } => "SourceAnnotationRefused", CompilerDiagnostic::ContainerSpellingUnrecognized { .. } => "ContainerSpellingUnrecognized", @@ -1710,6 +1712,9 @@ pub fn compile_clean_diagnostic_histogram_key(d: &Rc) -> (String, Str CompilerDiagnostic::TypeParameterInValuePosition { name, .. } => name.clone(), CompilerDiagnostic::EqualityOnFunctionMember { type_name, .. } => type_name.clone(), CompilerDiagnostic::EqualityMemberUnjudgeable { type_name, .. } => type_name.clone(), + CompilerDiagnostic::EqualityOptionalityMismatch { optional_side, .. } => { + optional_side.clone() + } CompilerDiagnostic::OccurrenceTransportViolation { .. } => { "(occurrence-transport-refusal)".to_string() } diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 029f18a7d97..05cf708c470 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -281,10 +281,10 @@ use crate::v1_std_core::CompilerDiagnostic::{ AlgebraApplicationEvidenceUnavailable, AmbiguousReference, BareNoneNotAdmittedByFieldType, CallArgumentDuplicate, CallArgumentNameUnknown, CallNamedArgOnFunctionValue, CallPositionalDeficit, CallPositionalSurplus, ConstructorCallAdmissionRefused, - EqualityMemberUnjudgeable, EqualityOnFunctionMember, FieldNotFound, - FrontierOccurrenceBudgetExceeded, InternalError, MethodExistenceFrontierAdmitted, - MethodExistenceUndecided, MethodNotFound, MissingField, OptionalCastNotEliminated, - ReceiverTypeUnestablished, ServiceConfigReferenceJudgmentDeferred, + EqualityMemberUnjudgeable, EqualityOnFunctionMember, EqualityOptionalityMismatch, + FieldNotFound, FrontierOccurrenceBudgetExceeded, InternalError, + MethodExistenceFrontierAdmitted, MethodExistenceUndecided, MethodNotFound, MissingField, + OptionalCastNotEliminated, ReceiverTypeUnestablished, ServiceConfigReferenceJudgmentDeferred, SiblingOperandEffectOrderUndetermined, SoleConstructorViolation, TextRepresentationUnidentifiedAtBoundary, TypeArgumentArityMismatch, TypeMismatch, TypeParameterInValuePosition, UnlistedVariantValueUse, UnresolvedType, VariantCollision, @@ -5026,6 +5026,22 @@ pub fn equality_operand_is_presence_literal( } } +pub fn equality_operand_is_optional( + n: Rc, + source_indices: Rc>>, +) -> bool { + match n.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: rt, .. }) => { + ((rt.return_cardinality.clone() == Cardinality::CardOptional) + || ((crate::v1_std_core::qualified_last_segment( + crate::v1_std_core::authored_name_at(source_indices.clone(), rt.clone()), + ) == "Optional".to_string()) + && ((rt.children.clone().len() as i64) == 1))) + } + _ => false, + } +} + pub fn equality_admission_refusal_diag( r: Rc, span: Rc, @@ -5101,18 +5117,32 @@ pub fn equality_admission_diags( { Rc::new(vec![]) } else { - match equality_operand_admission( - lt.clone(), - scope.clone(), - v1_rt::rc_empty_map::(), - 0, - ) { - Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( - equality_admission_refusal_diag(r.clone(), span.clone()), - scope.module_name.clone(), - )]), - std::option::Option::None => match equality_operand_admission( - rt.clone(), + if (equality_operand_is_optional(left_typed.clone(), source_indices.clone()) + != equality_operand_is_optional( + right_typed.clone(), + source_indices.clone(), + )) + { + { + let side = if equality_operand_is_optional( + left_typed.clone(), + source_indices.clone(), + ) { + "left".to_string() + } else { + "right".to_string() + }; + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::EqualityOptionalityMismatch { + optional_side: side.clone(), + span: span.clone(), + }), + scope.module_name.clone(), + )]) + } + } else { + match equality_operand_admission( + lt.clone(), scope.clone(), v1_rt::rc_empty_map::(), 0, @@ -5121,8 +5151,19 @@ pub fn equality_admission_diags( equality_admission_refusal_diag(r.clone(), span.clone()), scope.module_name.clone(), )]), - std::option::Option::None => Rc::new(vec![]), - }, + std::option::Option::None => match equality_operand_admission( + rt.clone(), + scope.clone(), + v1_rt::rc_empty_map::(), + 0, + ) { + Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( + equality_admission_refusal_diag(r.clone(), span.clone()), + scope.module_name.clone(), + )]), + std::option::Option::None => Rc::new(vec![]), + }, + } } } } diff --git a/src/v1/stage0/src/v1_std_core.rs b/src/v1/stage0/src/v1_std_core.rs index 158207f9b52..ca353598627 100644 --- a/src/v1/stage0/src/v1_std_core.rs +++ b/src/v1/stage0/src/v1_std_core.rs @@ -860,6 +860,10 @@ pub enum CompilerDiagnostic { member: String, span: Rc, }, + EqualityOptionalityMismatch { + optional_side: String, + span: Rc, + }, TypeArgumentArityMismatch { type_name: String, supplied: i64, @@ -1054,6 +1058,7 @@ pub fn diagnostic_to_span(d: Rc) -> Rc { CompilerDiagnostic::CallNamedArgOnFunctionValue { span: s, .. } => s.clone(), CompilerDiagnostic::EqualityOnFunctionMember { span: s, .. } => s.clone(), CompilerDiagnostic::EqualityMemberUnjudgeable { span: s, .. } => s.clone(), + CompilerDiagnostic::EqualityOptionalityMismatch { span: s, .. } => s.clone(), CompilerDiagnostic::TypeArgumentArityMismatch { span: s, .. } => s.clone(), CompilerDiagnostic::TypeArgumentKindMismatch { span: s, .. } => s.clone(), CompilerDiagnostic::TypeParameterInValuePosition { span: s, .. } => s.clone(), @@ -1131,6 +1136,7 @@ pub fn diagnostic_to_message(d: Rc) -> String { CompilerDiagnostic::CallNamedArgOnFunctionValue { callee: c, argument: a, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("call shape mismatch calling function value '".to_string(), c.clone()), "': named argument '".to_string()), a.clone()), "' is not supported — use positional arguments".to_string()), CompilerDiagnostic::EqualityOnFunctionMember { type_name: t, member: m, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("equality is not defined for '".to_string(), t.clone()), "': member '".to_string()), m.clone()), "' is function-valued, and function equality has no denotation — compare a declared identity for this type instead of '=='".to_string()), CompilerDiagnostic::EqualityMemberUnjudgeable { type_name: t, member: m, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("equality admission for '".to_string(), t.clone()), "' cannot be judged: ".to_string()), m.clone()), " — '==' is refused rather than admitted on an unjudged member".to_string()), + CompilerDiagnostic::EqualityOptionalityMismatch { optional_side: side, .. } => v1_rt::concat(v1_rt::concat("'==' compares an optional value with a required one (the ".to_string(), side.clone()), " operand is optional): no declared coercion lifts T into T?, so the comparison has no single meaning -- compare against Present { value: .. } or match on the optional".to_string()), CompilerDiagnostic::TypeArgumentArityMismatch { type_name: t, supplied: s, declared: d, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("type argument arity mismatch applying '".to_string(), t.clone()), "': ".to_string()), (s.clone()).to_string()), " type argument(s) supplied, ".to_string()), (d.clone()).to_string()), " type parameter(s) declared".to_string()), CompilerDiagnostic::TypeArgumentKindMismatch { type_name: t, param_name: p, kind_name: k, supplied: sup, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("type argument does not inhabit the declared kind applying '".to_string(), t.clone()), "': parameter '".to_string()), p.clone()), "' is declared '".to_string()), k.clone()), "', and '".to_string()), sup.clone()), "' is not one of its inhabitants".to_string()), CompilerDiagnostic::TypeParameterInValuePosition { name: n, .. } => v1_rt::concat(v1_rt::concat("'".to_string(), n.clone()), "' is a type parameter, not a value: a name bound as a type may not stand in an expression position".to_string()), @@ -1428,6 +1434,10 @@ pub fn diagnostic_disposition(d: Rc) -> Rc Rc::new(DiagnosticDisposition { severity: DiagnosticSeverity::SeverityError, gate: Rc::new(DiagnosticGateDisposition::GateBlocking), +}), + CompilerDiagnostic::EqualityOptionalityMismatch { .. } => Rc::new(DiagnosticDisposition { + severity: DiagnosticSeverity::SeverityError, + gate: Rc::new(DiagnosticGateDisposition::GateBlocking), }), CompilerDiagnostic::TypeArgumentArityMismatch { .. } => Rc::new(DiagnosticDisposition { severity: DiagnosticSeverity::SeverityError, From 1fb57a4068cb073ca9145ad91d1b14a90586b083 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 00:36:55 +0000 Subject: [PATCH 03/69] G: data rows keep their declared ? (preserve_outer_optional_cardinality at ModuleItemDataValue) Co-Authored-By: Claude Opus 5.5 (1M context) --- .../instruments/native_emission_controls.dag | 37 ++++++++++++++++++- src/v1/05_emit_rust.dag | 6 ++- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index e9ee493e680..f083b996b0f 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -1,6 +1,6 @@ module gunbc.instruments.native_emission_controls -import std.types { Bool, Int, List, Set, String } +import std.types { Bool, Int, List, NonEmptyStr, Set, String } import v2.std.algebra { filter } import std.compiler_entry { CompilerEntryDriver, NativeClaimDriver, NativeClaimReport, NativeClaimTerminal, NativeClaimHeld, NativeClaimNotHeld } @@ -129,6 +129,37 @@ fn filter_in_branch_condition_cases() -> List { ] } +// RULE: a data row keeps its declared `?` (v1.compiler.emit_rust, ModuleItemDataValue through +// preserve_outer_optional_cardinality). The `?` of `data d: T? = ..` lives on the item, not on its +// annotation node, and the branded-type arm of emit_data_def rendered from the annotation alone, so +// gunbc.fleet_tailnet fleet_tailnet_domain (`NonEmptyStr? = Present { .. }`) was emitted +// `-> NonEmptyStr` and its consumer refused (E0308, expected Option). Both rows here pass +// through a `T?`-typed parameter, so a dropped `?` stops this closure compiling; the cases then decide +// that the present row answers its value and the absent row answers Absent. +data control_optional_brand_present: NonEmptyStr? = Present { value: "tailnet.example" } + +data control_optional_brand_absent: NonEmptyStr? = none + +fn control_optional_brand_value(d: NonEmptyStr?) -> String { + match d { + Present { value: v } => v + Absent => "" + } +} + +fn optional_data_row_cases() -> List { + [ + NativeEmissionCase { + identity: "optional_data_row_present_answers_its_value", + held: control_optional_brand_value(d: control_optional_brand_present) == "tailnet.example" + }, + NativeEmissionCase { + identity: "optional_data_row_red_absent_answers_absent", + held: control_optional_brand_value(d: control_optional_brand_absent) == "" + } + ] +} + data native_emission_expected_identities: List = [ "set_struct_eq_same_members_in_another_order", "set_struct_eq_red_bare_field_differs", @@ -144,11 +175,13 @@ data native_emission_expected_identities: List = [ "filter_guard_nested_else_arm", "filter_guard_receipt_blank_tail_accepts", "filter_guard_receipt_red_nonblank_tail_refuses", + "optional_data_row_present_answers_its_value", + "optional_data_row_red_absent_answers_absent", "filter_guard_receipt_red_empty_tag_short_circuits" ] fn native_emission_cases() -> List { - concat(header_bound_cases(), filter_in_branch_condition_cases()) + concat(concat(header_bound_cases(), filter_in_branch_condition_cases()), optional_data_row_cases()) } fn case_row(c: NativeEmissionCase) -> String { diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 1ea1ac37481..c7b31a29a50 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -7532,7 +7532,11 @@ fn emit_typed_item(item: Node, module_name: String, registry: Map match item.body { Present { value: data_value } => { - emit_data_def(name: item_text, type_node: data_anno, value: data_value, registry: registry, scope: scope, depth: 0, shared_types: shared_types, emit_info: emit_info) + // The declaration's `?` lives on the ITEM, not on its annotation node (infer's + // declared_type_conformance_note class 4), so the declared type is rebuilt through + // the same authority fn returns use. Without it a branded `data d: NonEmptyStr? = + // Present { .. }` rendered `-> NonEmptyStr` and every consumer of the row refused. + emit_data_def(name: item_text, type_node: preserve_outer_optional_cardinality(outer: item, inner: data_anno), value: data_value, registry: registry, scope: scope, depth: 0, shared_types: shared_types, emit_info: emit_info) } Absent => emit_rust_item_refusal(item_text: item_text, reason: "data item carries no value") } From c0f8fc0c9a868c3580854b42e97bff5e34a8e8b5 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 00:46:37 +0000 Subject: [PATCH 04/69] C4: std.filesystem is_text_readable compares the symlink target as Present { value: TargetFile } Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/std/filesystem.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/std/filesystem.dag b/dag/std/filesystem.dag index adad9165863..cb28a28e4a0 100644 --- a/dag/std/filesystem.dag +++ b/dag/std/filesystem.dag @@ -27,7 +27,7 @@ type PartitionResult { fn is_text_readable(entry: FileEntry) -> Bool { match entry.kind { RegularFile => is_text_encoding_optional(e: entry.encoding) - Symlink => entry.symlink_target == TargetFile && is_text_encoding_optional(e: entry.encoding) + Symlink => entry.symlink_target == Present { value: TargetFile } && is_text_encoding_optional(e: entry.encoding) Directory => false Missing => false Other => false From 1ab64314f17260a09807cef203250a4ac4191307 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 00:56:47 +0000 Subject: [PATCH 05/69] G: import preserve_outer_optional_cardinality from v1.std.core Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/05_emit_rust.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index c7b31a29a50..a36a092a3b8 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -41,7 +41,7 @@ import v1.std.core { Unmarked, Node, InferredNode, Resolved, CompilerError, TypeVariable, is_compiler_error, import_is_all, import_specific_names_at, module_imports, module_items, param_node_type_expr, param_node_default_value, authored_name_at, NewlineIndex, find_child_named, tuple_type_name, - qualified_last_segment, expr_var_name_at, expr_call_func_at, field_access_field_at, + qualified_last_segment, preserve_outer_optional_cardinality, expr_var_name_at, expr_call_func_at, field_access_field_at, param_node_name_at, resource_use_name_at, field_binding_name_at, field_node_name_at, field_node_type_expr, generic_param_name_at, ExprData, NoExprData, ExprLiteral, ExprElaboratedLiteral, ExprError, ExprVar, ExprFieldAccess, ExprCall, ExprMethodCall, ExprMatch, ExprIf, ExprLet, From dd28d259c940f6dd5a6465310fb24d14184aa219 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 01:27:17 +0000 Subject: [PATCH 06/69] C4: make the five remaining T? == T sites explicit (.first() and indexing reads) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/github/expressions.dag | 5 ++++- dag/extdeps/sudo/nopasswd_execute_probe_check_op.dag | 5 ++++- dag/gunbc/floor_cost_distribution.dag | 6 +++--- .../optional_compared_with_required_value.dag | 2 ++ 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/dag/extdeps/github/expressions.dag b/dag/extdeps/github/expressions.dag index fd03c46d243..1fd6a8d1c3a 100644 --- a/dag/extdeps/github/expressions.dag +++ b/dag/extdeps/github/expressions.dag @@ -459,7 +459,10 @@ fn ingest_expression(src: String) -> Expression? { fn ingest_template_with(src: String, sp: ExpressionSpellings) -> ExpressionTemplate? { let parts = split(s: src, delimiter: sp.interp_open) - let lead = parts.first() + let lead = match parts.first() { + Present { value: l } => l + Absent => "" + } let lead_segs = if lead == "" { [] } else { [ LiteralText { text: lead } ] } let built = fold(parts.skip(n: 1), init: Present { value: lead_segs }, f: (acc, part) => match acc { Absent => none diff --git a/dag/extdeps/sudo/nopasswd_execute_probe_check_op.dag b/dag/extdeps/sudo/nopasswd_execute_probe_check_op.dag index 00030a41f1e..d4dd49f2584 100644 --- a/dag/extdeps/sudo/nopasswd_execute_probe_check_op.dag +++ b/dag/extdeps/sudo/nopasswd_execute_probe_check_op.dag @@ -44,7 +44,10 @@ fn sudo_nopasswd_grant_list_line_admits_probe( if length(xs: parts) != 2 { false } else { - parts.skip(n: 1).first().trim() == probe as String + match parts.skip(n: 1).first() { + Present { value: second } => second.trim() == probe as String + Absent => false + } } } diff --git a/dag/gunbc/floor_cost_distribution.dag b/dag/gunbc/floor_cost_distribution.dag index 94051562cab..b0fee935a30 100644 --- a/dag/gunbc/floor_cost_distribution.dag +++ b/dag/gunbc/floor_cost_distribution.dag @@ -471,9 +471,9 @@ fn censored_eval_steps(fields: List, columns: ClaimCostColumns) -> Int? } fn parse_claim_cost_reading(fields: List, columns: ClaimCostColumns) -> ClaimCostReading? { - if fields[columns.cost_reading] == "observed" { + if fields[columns.cost_reading] == Present { value: "observed" } { observed_cost_reading(fields: fields, columns: columns) - } else if fields[columns.cost_reading] == "right_censored" { + } else if fields[columns.cost_reading] == Present { value: "right_censored" } { right_censored_cost_reading(fields: fields, columns: columns) } else { none @@ -530,7 +530,7 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo ) if count(fields) <= widest { none - } else if fields[columns.identity] == "identity" { + } else if fields[columns.identity] == Present { value: "identity" } { none } else { match parse_claim_cost_reading(fields: fields, columns: columns) { diff --git a/dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag b/dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag index ba933675973..f792139dffb 100644 --- a/dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag +++ b/dag/gunbc/recurring_failure_mode/optional_compared_with_required_value.dag @@ -15,6 +15,8 @@ data optional_compared_with_required_value: RecurringFailureMode = RecurringFail "WALL: v1.compiler.infer equality_admission_diags refuses Eq/Ne when exactly one operand's resolved type is optional (CardOptional on the typed operand, the fact the emitter reads, or the nominal Optional coproduct), as the blocking EqualityOptionalityMismatch. The presence idiom (`== none`, `== Absent`, `== []`) is exempt before the arm runs, as it already was for the function-member wall. Each refused corpus site was rewritten to say the meaning it intends (an explicit Present comparison or a match), never by inserting a lift.", + "THE POPULATION IS WIDER THAN OPTIONAL FIELDS, measured by the floor's strict compile over 2565 modules once the arm landed: six sites, and five were not record fields at all but the two optional-returning list reads -- `.first()` (extdeps.github.expressions ingest_template_with; extdeps.sudo.nopasswd_execute_probe_check_op) and indexing `xs[i]` (three sites in gunbc.floor_cost_distribution). Each was written as if the read returned the element. The interpreter happened to answer them by the bare-representation arm, which is why they never failed: the program was right only because of how a value was stored.", + "EVIDENCE: test.claim.self_host_equality_admission_witness. Reds: a `Kind?` field compared with a bare variant in both operand orders, each refused once and blocking. Controls: an explicit `== Present { value: .. }`, a match on the optional, and two optionals compared with each other, all admitted.", "RUNG FOUND AT: below the ladder on the interpretation path (silent, representation-dependent answer), 1 on the Rust emission path (rustc refusal).", From 1c9bf792c529dfa584403e37da74da7d01130508 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 01:36:28 +0000 Subject: [PATCH 07/69] G: move the rationale to module-item grain (a body annotation is refused, DESIGN 4c) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/05_emit_rust.dag | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index a36a092a3b8..3ab73d8bd57 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -7532,10 +7532,6 @@ fn emit_typed_item(item: Node, module_name: String, registry: Map match item.body { Present { value: data_value } => { - // The declaration's `?` lives on the ITEM, not on its annotation node (infer's - // declared_type_conformance_note class 4), so the declared type is rebuilt through - // the same authority fn returns use. Without it a branded `data d: NonEmptyStr? = - // Present { .. }` rendered `-> NonEmptyStr` and every consumer of the row refused. emit_data_def(name: item_text, type_node: preserve_outer_optional_cardinality(outer: item, inner: data_anno), value: data_value, registry: registry, scope: scope, depth: 0, shared_types: shared_types, emit_info: emit_info) } Absent => emit_rust_item_refusal(item_text: item_text, reason: "data item carries no value") @@ -16715,6 +16711,11 @@ fn data_def_annotation_is_named_refinement(annotation: Node, source_indices: Map // declared type decided by the carrier and its wrap decided by the spelling, and needs_rc is // threaded into emit_data_def_body, so the value took the same answer as the signature. Routed to // the carrier authority; the spelling key is deleted rather than kept beside it. +// A DATA ROW'S DECLARED `?` LIVES ON THE ITEM, not on its annotation node (infer's +// declared_type_conformance_note class 4), so the ModuleItemDataValue caller hands this function the +// annotation rebuilt through preserve_outer_optional_cardinality -- the same authority fn returns use. +// Without it a branded `data d: NonEmptyStr? = Present { .. }` rendered `-> NonEmptyStr` here (the +// preserves_declared_brand arm renders from the annotation alone) and every consumer refused. fn emit_data_def(name: String, type_node: Node, value: Node, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { let annotation_type_node = type_node let ann_name = authored_name_at(source_indices: scope.type_env.source_indices, node: annotation_type_node) From deee2b890a23985387aba17429115387975f0bcf Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 02:14:54 +0000 Subject: [PATCH 08/69] list index realized as the optional it is typed as (Rust): explicit absence at every census site, index carve-out deleted Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/extdeps/linux/proc_mountinfo.dag | 14 +- dag/gunbc/floor_cost_distribution.dag | 61 ++-- .../instruments/native_emission_controls.dag | 43 ++- ...ional_but_realized_as_the_bare_element.dag | 4 +- ...ted_where_a_required_value_is_declared.dag | 4 +- .../self_host_compile_phase_frontier.dag | 2 +- ...onal_at_required_position_witness_test.dag | 39 ++- src/v1/01_tokenize.dag | 328 +++++++++--------- src/v1/04_infer.dag | 53 +-- src/v1/languages.dag | 4 +- 10 files changed, 295 insertions(+), 257 deletions(-) diff --git a/dag/extdeps/linux/proc_mountinfo.dag b/dag/extdeps/linux/proc_mountinfo.dag index a14fa0316ef..96e5928e701 100644 --- a/dag/extdeps/linux/proc_mountinfo.dag +++ b/dag/extdeps/linux/proc_mountinfo.dag @@ -38,12 +38,14 @@ fn mountinfo_mount_points(content: String) -> MountinfoMountPoints { Present { value: _ } => acc Absent => { let fields = split(s: line, delimiter: " ") - if length(fields) <= mountinfo_mount_point_field_index { - MountinfoFold { points: acc.points, refusal: Present { value: MountPointsUndecodable { line: line, cause: "the line has fewer than five fields, so it names no mount point" as NonEmptyStr } } } - } else if string_contains(s: fields[mountinfo_mount_point_field_index], pattern: "\\") { - MountinfoFold { points: acc.points, refusal: Present { value: MountPointsUndecodable { line: line, cause: "the mount point carries a kernel octal escape, which this model does not decode" as NonEmptyStr } } } - } else { - MountinfoFold { points: list_push(acc.points, fields[mountinfo_mount_point_field_index]), refusal: none } + match fields[mountinfo_mount_point_field_index] { + Absent => MountinfoFold { points: acc.points, refusal: Present { value: MountPointsUndecodable { line: line, cause: "the line has fewer than five fields, so it names no mount point" as NonEmptyStr } } } + Present { value: point } => + if string_contains(s: point, pattern: "\\") { + MountinfoFold { points: acc.points, refusal: Present { value: MountPointsUndecodable { line: line, cause: "the mount point carries a kernel octal escape, which this model does not decode" as NonEmptyStr } } } + } else { + MountinfoFold { points: list_push(acc.points, point), refusal: none } + } } } }, diff --git a/dag/gunbc/floor_cost_distribution.dag b/dag/gunbc/floor_cost_distribution.dag index 94051562cab..7eec8739cf0 100644 --- a/dag/gunbc/floor_cost_distribution.dag +++ b/dag/gunbc/floor_cost_distribution.dag @@ -386,10 +386,28 @@ fn claim_cost_columns(header_line: String) -> ClaimCostColumns? { // The acceptance-path disagreement itself is NOT diagnosed by this edit and is reported separately; // re-spelling until the checker stops complaining would have been the authoring-time workaround // DESIGN section 5 names, so this is a decomposition that stands on its own terms. +// A CELL THE ROW DOES NOT CARRY IS NOT A FIGURE. `fields[ix]` answers `String?` (an index past the +// row has no cell), and a missing cell reads exactly as an unparseable one: no reading. The width +// guard in parse_claim_cost_line refuses a torn row first, so this is the index's own typed answer +// rather than a recovery. +fn field_int(fields: List, ix: Int) -> Int? { + match fields[ix] { + Present { value: cell } => parse_int(s: cell) + Absent => none + } +} + +fn field_is(fields: List, ix: Int, want: String) -> Bool { + match fields[ix] { + Present { value: cell } => cell == want + Absent => false + } +} + fn observed_cost_reading(fields: List, columns: ClaimCostColumns) -> ClaimCostReading? { - match parse_int(s: fields[columns.observed_cpu_ms]) { + match field_int(fields: fields, ix: columns.observed_cpu_ms) { Absent => none - Present { value: cpu } => match parse_int(s: fields[columns.eval_steps]) { + Present { value: cpu } => match field_int(fields: fields, ix: columns.eval_steps) { Absent => none Present { value: steps } => Present { value: ObservedCpuReading { @@ -418,7 +436,7 @@ fn observed_cost_reading(fields: List, columns: ClaimCostColumns) -> Cla // reason: it answers a question that is not the cost reading, so an artifact lacking it is still a // sound cost artifact and only the ceiling-relative question is unavailable over it. fn right_censored_cost_reading(fields: List, columns: ClaimCostColumns) -> ClaimCostReading? { - match parse_int(s: fields[columns.cpu_at_least_ms]) { + match field_int(fields: fields, ix: columns.cpu_at_least_ms) { Absent => none Present { value: bound } => match censored_eval_steps(fields: fields, columns: columns) { Absent => none @@ -429,7 +447,7 @@ fn right_censored_cost_reading(fields: List, columns: ClaimCostColumns) eval_steps_before_censor: eval_step_count(count: steps) } } - Present { value: ceiling_ix } => match parse_int(s: fields[ceiling_ix]) { + Present { value: ceiling_ix } => match field_int(fields: fields, ix: ceiling_ix) { Absent => none Present { value: ceiling } => Present { value: RightCensoredCpuReading { @@ -461,19 +479,19 @@ fn right_censored_cost_reading(fields: List, columns: ClaimCostColumns) // that is where the producer wrote it. Refusing those rows would retire the reader against every // run before the split, which is the same trade the optional ceiling column already makes. fn censored_eval_steps(fields: List, columns: ClaimCostColumns) -> Int? { - match parse_int(s: fields[columns.eval_steps]) { + match field_int(fields: fields, ix: columns.eval_steps) { Present { value: performed } => Present { value: performed } Absent => match columns.eval_steps_at_least { Absent => none - Present { value: ix } => parse_int(s: fields[ix]) + Present { value: ix } => field_int(fields: fields, ix: ix) } } } fn parse_claim_cost_reading(fields: List, columns: ClaimCostColumns) -> ClaimCostReading? { - if fields[columns.cost_reading] == "observed" { + if field_is(fields: fields, ix: columns.cost_reading, want: "observed") { observed_cost_reading(fields: fields, columns: columns) - } else if fields[columns.cost_reading] == "right_censored" { + } else if field_is(fields: fields, ix: columns.cost_reading, want: "right_censored") { right_censored_cost_reading(fields: fields, columns: columns) } else { none @@ -530,10 +548,14 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo ) if count(fields) <= widest { none - } else if fields[columns.identity] == "identity" { + } else if field_is(fields: fields, ix: columns.identity, want: "identity") { none } else { - match parse_claim_cost_reading(fields: fields, columns: columns) { + match fields[columns.identity] { + Absent => none + Present { value: identity } => match fields[columns.module] { + Absent => none + Present { value: module } => match parse_claim_cost_reading(fields: fields, columns: columns) { Absent => none Present { value: reading } => match (match fields.skip(n: columns.verdict_reached).first() { Absent => none Present { value: cell } => parse_verdict_reached(value: cell) }) { Absent => none @@ -541,8 +563,8 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo ReachabilityColumnUnreadable => none ReachabilityColumnUnrecorded => Present { value: FloorCostRow { - identity: fields[columns.identity], - module: fields[columns.module], + identity: identity, + module: module, verdict_reached: reached, cost: reading, reachability: none @@ -550,8 +572,8 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo } ReachabilityColumnRead { value: reach } => Present { value: FloorCostRow { - identity: fields[columns.identity], - module: fields[columns.module], + identity: identity, + module: module, verdict_reached: reached, cost: reading, reachability: Present { value: reach } @@ -560,6 +582,8 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo } } } + } + } } } } @@ -1061,12 +1085,9 @@ fn identity_inflation_permille(base: RunCost, other: RunCost, min_base_ms: Milli fn permille_percentile(values: List, percent: Int) -> Int? { let sorted = values |> sort_by(v => v) let n = count(sorted) - if n == 0 { - none - } else { - let idx = (percent * n) / 100 - if idx >= n { Present { value: sorted[n - 1] } } else { Present { value: sorted[idx] } } - } + let idx = (percent * n) / 100 + // The index read is the answer: an empty input has no member at any rank, so it is absent. + if idx >= n { sorted[n - 1] } else { sorted[idx] } } // THE MARGIN THE MEASURED INFLATION IMPLIES: the largest clean-run cost that still lands under the diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index e9ee493e680..ca8c814034e 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -129,6 +129,39 @@ fn filter_in_branch_condition_cases() -> List { ] } +// RULE: a list index is realized as the optional its type says it is. v1.compiler.infer_access +// check_index_access_node types `xs[i]` as `T?`, an out-of-range index having no element, and the +// Rust list_index template (v1.compiler.languages) used to print the bare `xs[i as usize].clone()`, +// which panics out of range and is no Option to match -- rustc refused every carrier below. It is +// now `.get(i as usize).cloned()`, so the elimination the type demands is a program and an absent +// index is the Absent arm (gunbc.recurring_failure_mode +// list_index_typed_optional_but_realized_as_the_bare_element). A negative index is out of range +// on the same footing: it has no element. +fn index_reads_value(xs: List, i: Int, want: Int) -> Bool { + match xs[i] { + Present { value: v } => v == want + Absent => false + } +} + +fn index_reads_absent(xs: List, i: Int) -> Bool { + match xs[i] { + Present { value: _ } => false + Absent => true + } +} + +fn list_index_cases() -> List { + [ + NativeEmissionCase { identity: "list_index_in_range_yields_the_element", held: index_reads_value(xs: [10, 20, 30], i: 1, want: 20) }, + NativeEmissionCase { identity: "list_index_red_in_range_is_not_another_element", held: !index_reads_value(xs: [10, 20, 30], i: 1, want: 10) }, + NativeEmissionCase { identity: "list_index_red_in_range_is_not_absent", held: !index_reads_absent(xs: [10, 20, 30], i: 2) }, + NativeEmissionCase { identity: "list_index_past_the_end_is_absent", held: index_reads_absent(xs: [10, 20, 30], i: 3) }, + NativeEmissionCase { identity: "list_index_negative_is_absent", held: index_reads_absent(xs: [10, 20, 30], i: 0 - 1) }, + NativeEmissionCase { identity: "list_index_into_empty_is_absent", held: index_reads_absent(xs: [], i: 0) } + ] +} + data native_emission_expected_identities: List = [ "set_struct_eq_same_members_in_another_order", "set_struct_eq_red_bare_field_differs", @@ -144,11 +177,17 @@ data native_emission_expected_identities: List = [ "filter_guard_nested_else_arm", "filter_guard_receipt_blank_tail_accepts", "filter_guard_receipt_red_nonblank_tail_refuses", - "filter_guard_receipt_red_empty_tag_short_circuits" + "filter_guard_receipt_red_empty_tag_short_circuits", + "list_index_in_range_yields_the_element", + "list_index_red_in_range_is_not_another_element", + "list_index_red_in_range_is_not_absent", + "list_index_past_the_end_is_absent", + "list_index_negative_is_absent", + "list_index_into_empty_is_absent" ] fn native_emission_cases() -> List { - concat(header_bound_cases(), filter_in_branch_condition_cases()) + concat(concat(header_bound_cases(), filter_in_branch_condition_cases()), list_index_cases()) } fn case_row(c: NativeEmissionCase) -> String { diff --git a/dag/gunbc/recurring_failure_mode/list_index_typed_optional_but_realized_as_the_bare_element.dag b/dag/gunbc/recurring_failure_mode/list_index_typed_optional_but_realized_as_the_bare_element.dag index a81745a9e14..41e1f054816 100644 --- a/dag/gunbc/recurring_failure_mode/list_index_typed_optional_but_realized_as_the_bare_element.dag +++ b/dag/gunbc/recurring_failure_mode/list_index_typed_optional_but_realized_as_the_bare_element.dag @@ -10,7 +10,9 @@ data list_index_typed_optional_but_realized_as_the_bare_element: RecurringFailur "HARM, in both directions. Where the emitter acts on the declared type it emits a coercion the realization cannot satisfy: the note on v1.tokenize code_point_at records `chars[i]` passed to a declared parameter emitting `.expect(..)` on an i64 (E0599), transcribed from that note and not re-executed by the change filing this row. Where a consumer ignores the type, an out-of-range index reaches a Required position: on interpretation as an absent value with no refusal, on the Rust path as a panic. Either way the floor obligation that values inhabit declared types (DESIGN 4b) is not decided for an index value, and any wall that reads cardinality must either refuse code the realization cannot repair or carve the index out.", "RECEIPT, gunbc#12791 (2026-09-30), executed. The optional-at-required wall reached the declared-return position and the second-generation regeneration (`claim_executor --required-regen`, the rebuilt seed compiling its own sources) refused with two DeclaredTypeNotInhabited rows, declared Int and produced optional Int, at v1.tokenize source_code_point and v1.tokenize code_point_at, both returning `chars[pos]`. The note on code_point_at had predicted exactly this: the accessors work because return position was not checked, and return-position typechecking would red them together. The wall therefore carries a declared carve-out for index values, whose counted population lives on gunbc.recurring_failure_mode.optional_admitted_where_a_required_value_is_declared.", "DISTINGUISHING FACTS: `.first()`, `.last()` and `.get(index:)` are typed optional AND eliminated by match in code the same change repaired and compiled, so the disagreement is specific to the index expression form, not to optional collection access in general. The seed's tokenizer depends on the bare realization on its hottest path, which is why the reconciliation is a seed change with a cost question attached and not a consumer rewrite.", - "RUNG FOUND AT AND CURRENT RUNG: silent, below the floor -- no check decides whether an index value may be absent at the position it reaches, on either path. CEILING: structurally guaranteed; both reconciliations are decidable from modeled facts.", + "RUNG FOUND AT: silent, below the floor -- no check decided whether an index value may be absent at the position it reaches, on either path. CEILING: structurally guaranteed; both reconciliations are decidable from modeled facts.", + "CLIMB, trigger arm (a) on the Rust target (native broker lane 2I, 2026-10-04). The Rust list_index template in v1.compiler.languages is `({0}).get(({1}) as usize).cloned()`, the shape map_index already had, so an out-of-range or negative index realizes as the Absent arm instead of a panic. CENSUS before the change, every `xs[i]` read outside string literals and comments: the seed closure emitted nine (stage0 v1_compiler_tokenize.rs, all in v1.tokenize), src/v2 and gunbc.auth (the broker) none, and the dag corpus eighteen interpreted reads (gunbc.floor_cost_distribution fifteen, extdeps.linux.proc_mountinfo two, gunbc.self_host_compile_phase_frontier one). None was consumed as `T?`; every one relied on the implicit `T?` into `T`. Each now says what absence means at its site: the tokenizer accessor answers `Int?` and its consumers match (end of input, an unterminated string or escape, or a predicate that is false of no character); a floor-cost cell the row does not carry reads as no figure; a mountinfo line too short to name a mount point refuses by the arm it already had; the phase-frontier file prefix is read with take, not an index. There is no unwrap or panic helper. v1.compiler.infer expr_value_is_index_access is deleted with its produced_by threading, so the optional-at-required wall reaches index values. CONTROLS: gunbc.instruments.native_emission_controls list_index_cases (emitted, built and run under gunbc test //gunbc/instruments:native-emission-controls; on the bare template rustc refuses the carrier, a match on an i64), and test.claim.optional_at_required_position_witness_test an_index_access_at_a_required_position_refuses with its positive control an_index_access_eliminated_by_a_match_compiles_as_rust.", + "CURRENT RUNG AND RESIDUAL. Rust: structurally guaranteed at the four declared-type positions the wall judges (record-literal field, declared return, let annotation, data initializer). NOT YET on three paths, so the class minimum stays below ceiling: (1) the Python and Go list_index templates still print the bare `{0}[{1}]`, which raises or panics out of range -- next trigger, those templates realize the target's own optional carrier; (2) an index read at a comparison, field access or call argument is still admitted as `T` by the checker (optional into required at those positions is lane 2C's C4 wall, which lands after this) -- after this change an argument site realizes as the emitter's optional-to-required coercion and would panic, and none remains in the emitted seed, but nothing refuses a new one until C4; the interpreted tests carry four such comparison reads; (3) a String index is typed as the element, not optional, and is a separate class not judged here.", "NEXT-RUNG TRIGGER, the capability, either arm sufficient: (a) an index is realized optional on every target wherever it is typed optional, so a match on it is satisfiable and the accessors above eliminate it like any other optional; or (b) an index is admitted only where it is proven in bounds and is then typed as the element, with the unproven form refused. Sufficient for deleting v1.compiler.infer expr_value_is_index_access and the three tokenizer accessors' reliance on an unchecked return. Not satisfied by changing the typing alone or the emission alone, which moves the disagreement rather than removing it.", ], evidence: [], diff --git a/dag/gunbc/recurring_failure_mode/optional_admitted_where_a_required_value_is_declared.dag b/dag/gunbc/recurring_failure_mode/optional_admitted_where_a_required_value_is_declared.dag index 47d33365dc0..98d23b3dc5e 100644 --- a/dag/gunbc/recurring_failure_mode/optional_admitted_where_a_required_value_is_declared.dag +++ b/dag/gunbc/recurring_failure_mode/optional_admitted_where_a_required_value_is_declared.dag @@ -15,12 +15,12 @@ data optional_admitted_where_a_required_value_is_declared: RecurringFailureMode "THE CHAIN (DESIGN 6b), and why the repair is producers rather than a guard. The relation that decides an optional at a required position already existed and was already single: v1.compiler.infer optional_produced_at_required_declared, consulted first by declared_type_inhabitance. What was missing was upstream of it: the record-literal field chain and declared_type_conformance_diags (declared return, early return, let annotation, data initializer) never built an obligation, and compared the two types through node_type_compatible, which reads the type name and not return_cardinality. That relation is undirected -- it is also asked of branch pairs and of the lift direction -- so teaching it cardinality would have refused correct code; optional-into-required is a DIRECTED fact about a declared position, which is what DeclaredTypeObligation carries. The earliest unjustified boundary is therefore the absent producer, and the repair is optional_at_required_obligation_diags: those four seams build the same obligation, consult the same predicate, and emit the same DeclaredTypeNotInhabited naming the position, the field or binding, and both cardinalities. The undeclared list-literal member producer was folded onto it, so no second rendering of the verdict remains.", "TWO FABRICATED REFUSALS FOUND BY THE CENSUS AND REPAIRED AT THE PREDICATE, NOT AT SITES. (a) A coproduct that declares its own `Absent` arm (std.upsert_decision ObservationVerdict, gunbc.host.host_converge ConvergeVerdict): the bare arm is typed as the kernel Optional coproduct, so the produced side is optional BY NAME ONLY. Sixteen correct sites newly refused, and six more already stood refused on main at the direct-call argument in test.claim.fleet.fleet_converge_cli_witness_test, a fabricated refusal the first landing of this wall shipped. The predicate now abstains when the produced side carries no CardOptional and the declared coproduct owns `Absent` or `Present`. The defect it stands in for is upstream and open: variant-reference election ignores the declared coproduct and chooses the kernel Optional's Absent. Its owner is the value-position identity lane (deep-bee-18, session eager-ibex-722, routed by quiet-gull-780 on gunbc#12791); this row does not repair it. (b) An index access: v1.compiler.infer_access types `xs[i]` optional while its Rust realization is the bare element, and the seed's own tokenizer (v1.tokenize source_code_point, code_point_at) returns `chars[pos]` at a declared Int, as the note on code_point_at predicted. The second-generation regeneration refused on exactly those two. The optionality of an index value is not established across the two acceptance paths, so a value whose tail expression is an index access raises no obligation at the four new positions (expr_value_is_index_access).", "POPULATION OF THE SECOND LANDING (the whole-root compile differential; the instrument is named on gunbc.rung_drop.compiler_change_refusals_land_outside_every_compiled_closure, `gunbc compile --source-root dag --source-root src/v2 --target dag --repository gunbc --measured-root-demands tools/whole_corpus_compile_measured_root_demands.json`, base and head run sequentially on one frozen tree and joined on verbatim message plus location). Every newly refused identity is listed on the change that filed this receipt, each repaired or dispositioned there; the counts are that join's and are not restated here. The shapes: `.first()` / `.last()` / `first(..)` consumed as the element behind a length guard (the large majority, as in the first landing); `parse_int` into an Int field twice more, the exact specimen; a `T?` policy field read as `T`; and one explicit `Present { .. }` wrapper returned where the coproduct itself was declared. SCOPE, stated because it is narrower than WHOLE CORPUS: the join covers the dag-primary population only. A src/v2-primary whole-root compile refuses at admission with WholeCorpusCompileUnmeasuredRoot, so src/v2 modules are covered only where the dag root reaches them, and the modules that compile enters in the name census only are not covered at all. Both are UNMEASURED populations, not zeros: nothing here says they hold no optional at a required position.", - "THE INDEX CARVE-OUT IS A DECLARED RESIDUAL POPULATION, COUNTED AT IDENTITY GRAIN, NOT A SILENT EXCLUSION. Membership: a value whose tail expression is an index access standing at a record-literal field, declared return, let annotation or data initializer whose declared type is Required. MEASURED MEMBERS, six, each refused by the wall before the exclusion and admitted after it: v1.tokenize source_code_point (declared return) and v1.tokenize code_point_at (declared return), found by the second-generation regeneration; gunbc.floor_cost_distribution parse_claim_cost_line, four record-literal fields (identity and module, in each of its two row literals), found by the dag-primary whole-root compile. The instrument for the dag-primary members is the head-before-exclusion side of the differential named above; nothing outside that population or the seed's own sources was measured, so six is the measured membership and not a bound on the class. WHAT IS LOST: at those sites an out-of-range index reaches a Required position as an absent value on the interpretation path with no refusal, which is this row's invalid state. WHY IT IS NOT REPAIRED AT THE SITES: eliminating the optional with a match authors an elimination the Rust realization of an index (the bare element) cannot satisfy; the disagreement is its own class, gunbc.recurring_failure_mode.list_index_typed_optional_but_realized_as_the_bare_element. TRIGGER, THE CAPABILITY: the typing and the realization of `xs[i]` agree -- the index is typed optional AND realized optional on every target, or an index is admitted only where it is proven in bounds and is then typed as the element. Either is sufficient to delete v1.compiler.infer expr_value_is_index_access, at which point the six members refuse or are proven and leave. ENROLLED: test.claim.optional_at_required_position_witness_test an_index_access_at_a_required_position_is_the_declared_residual pins the admission and flips to a refusal count when the trigger lands.", + "THE INDEX CARVE-OUT WAS A DECLARED RESIDUAL OF SIX MEASURED MEMBERS AND IS DISCHARGED. v1.tokenize source_code_point and code_point_at (declared returns) and gunbc.floor_cost_distribution parse_claim_cost_line (four record-literal fields) stood admitted by v1.compiler.infer expr_value_is_index_access while the Rust realization of `xs[i]` was the bare element. Its trigger, typing and realization agreeing, landed on the Rust target (gunbc.recurring_failure_mode list_index_typed_optional_but_realized_as_the_bare_element, CLIMB): the predicate is deleted, code_point_at is deleted, source_code_point answers `Int?`, and the floor-cost fields are bound by a match. ENROLLED: test.claim.optional_at_required_position_witness_test an_index_access_at_a_required_position_refuses, flipped from the admission it used to pin.", "RESIDUALS, named. (1) The index population above. (2) Arguments of BUILTIN and method calls: the direct-call seam judges declared functions, so `parse_int(s: lines.first())` and join's receiver are unjudged. (3) A list literal whose HEAD element is optional elects List. (4) The five DeclaredTypePosition members with no producer (map value, variant payload, cast target, parameter default, callable return). (5) The interpreter's String-context rendering of a variant, unchanged from the first landing. (6) The v2 judge: v2.std.inhabitance answers UndecidableOptionalCarrier for a cardinality node on EITHER side and v2.compiler.infer admits that verdict, so v2 admits an optional at a required position; read from source, not executed, and reported to the owning lane rather than repaired here.", "THE V2 ROUTE, a separate path with its own rung (2026-09-30). v2.std.inhabitance declared_type_inhabitance carried the same misfiling: inhabitance_node_undecidable_reason answered UndecidableOptionalCarrier for a Cardinality type node on EITHER side, so a produced T? at a declared required type was admitted with an advisory. It was not reachable from source until gunbc#12777, because infer refused any tree carrying a Cardinality node for descent first (measured on main and on gunbc#12566: infer_descent_not_derived for `fn f(x: Int?) -> Int { x }`); with that change the program was ACCEPTED. The relation now refuses the pair by its own reason, inhabitance_optional_produced_at_required_declared. CURRENT RUNG on the v2 resolve-to-infer route: structurally guaranteed where the declared type is a kernel value type (an atom the judge denotes), at a declared return and at a record field, both executed from source text by v2.test.claim.compiler.infer_optional_at_required_witness_test. COUNTED, NOT REFUSED: a produced optional at a declared declaration reference, a declared Instantiation or a declared type variable, because the relation unfolds no alias and cannot know those are required (`type Maybe = Int?` is a declaration reference); trigger: the relation reads a declared type's resolved declaration, the capability gunbc#12726 PR2 provides. NOT YET ON THE ROUTE: a direct-call argument, because a named call's callee is not typed by its declaration (gunbc#12506); the relation refuses the pair, and the route claim is owed when that lands.", "HARM: silent wrongness, outside the ladder -- the output is plausible bytes, not a crash, and it was committed as a fixture by an automated heal.", "RUNG FOUND AT: silent, below the floor. CURRENT RUNG, at the grain of source to v1 acceptance: structurally guaranteed for a non-index optional value at the direct-call argument, declared list element, undeclared list-literal member, record-literal field, declared return (trailing expression and early return), let annotation and data initializer -- DeclaredTypeNotInhabited naming position, subject, declared and produced types with cardinality. Silent at the residual positions above, so the class as a whole is not at that rung and this row does not claim it. CEILING: structurally guaranteed (typecheck refusal); decidable from the two resolved types.", - "NEXT-RUNG TRIGGERS, as capabilities. FIRST: the index model and its realization agree (an index realizes as an optional, or types as its element), sufficient to delete expr_value_is_index_access and flip its enrolled claim. SECOND: variant-reference election consults the declared coproduct, sufficient to delete the by-name-only exclusion. THIRD: builtin and method call arguments raise a DeclaredTypeObligation. FOURTH: the four cardinality-only positions hand their obligation to declared_type_obligation_diags, deleting their older chains. Fixtures: test.claim.optional_at_required_position_witness_test.", + "NEXT-RUNG TRIGGERS, as capabilities. FIRST (discharged on the Rust target, see the carve-out receipt above): the index model and its realization agree. SECOND: variant-reference election consults the declared coproduct, sufficient to delete the by-name-only exclusion. THIRD: builtin and method call arguments raise a DeclaredTypeObligation. FOURTH: the four cardinality-only positions hand their obligation to declared_type_obligation_diags, deleting their older chains. Fixtures: test.claim.optional_at_required_position_witness_test.", "RECEIPT 2026-09-29, AN UNJUDGED POSITION NOT IN THE LIST ABOVE: FIELD PROJECTION. A field read through an Optional is admitted: `xs.first().id`, where `.first()` produces T? and Absent has no `id` field. The same `.first()` at a direct-call argument refuses. Found by review 72657 on gunbc#12572, at test.claim.machine_shape_catalog_integration_witness `memory.first().id` (and `.transfer_grain`). The whole-corpus compile that refused that file's call-argument sites reported nothing at those reads. That is a silent below-floor admission: whatever the interpreter does at the projection, no Accepted program should hold it, and the compiler does not decide it. The discriminating pair is in test.claim.optional_field_read_admission_gap_witness_test: one source shape is compiled twice, once consuming `.first()` at a field read (admitted today, zero blocking rows) and once at a call argument (refused, DeclaredTypeNotInhabited). NEXT-RUNG TRIGGER, added to the one above: the field-projection position routes through the same relation. The admission claim then flips to a regression control asserting the refusal.", ], evidence: [], diff --git a/dag/gunbc/self_host_compile_phase_frontier.dag b/dag/gunbc/self_host_compile_phase_frontier.dag index dd75c321be0..095dbe7c224 100644 --- a/dag/gunbc/self_host_compile_phase_frontier.dag +++ b/dag/gunbc/self_host_compile_phase_frontier.dag @@ -866,7 +866,7 @@ fn board_added_identities(previous: RustcPhaseBoard, current: RustcPhaseBoard) - } fn diagnostic_identity_file(identity: String) -> String { - let location = split(s: split(s: identity, delimiter: "\t")[0], delimiter: ":") + let location = split(s: split(s: identity, delimiter: "\t") |> take(n: 1) |> join(separator: ""), delimiter: ":") location.take(n: count(location) - 2) |> join(separator: ":") } diff --git a/dag/test/claim/optional_at_required_position_witness_test.dag b/dag/test/claim/optional_at_required_position_witness_test.dag index 22ec664a067..badba0b1c23 100644 --- a/dag/test/claim/optional_at_required_position_witness_test.dag +++ b/dag/test/claim/optional_at_required_position_witness_test.dag @@ -263,17 +263,30 @@ test fn a_coproducts_own_absent_arm_at_its_declared_positions_still_compiles() - ) } -// THE DECLARED RESIDUAL, ENROLLED AS WHAT IT IS. An index access types as optional and realizes in -// Rust as the bare element, so its optionality is not established across the two acceptance paths -// and these positions raise no cardinality obligation for it (v1.compiler.infer -// expr_value_is_index_access; the seed's own tokenizer returns `chars[pos]` at a declared Int). -// This claim pins the admission so the residual is an executed fact rather than a sentence: it -// goes red the day the index model and its realization are reconciled and the wall reaches index -// values, and on that day it flips to a refusal count, it does not retire. -fn oar_index_residual_source() -> String { - "module oar.index_residual\n\nimport std.types { Int, String }\n\ntype Code { code: Int }\n\nfn probe(xs: List) -> Int {\n xs[0]\n}\n\nfn probe_field(xs: List) -> Code {\n Code { code: xs[0] }\n}\n" -} - -test fn an_index_access_at_a_required_position_is_the_declared_residual() -> Bool { - not_inhabited_blocking_count(source: oar_index_residual_source()) == 0 +// AN INDEX AT A REQUIRED POSITION REFUSES. `xs[i]` types as optional (v1.compiler.infer_access +// check_index_access_node) and its Rust realization is the optional `.get(i).cloned()`, so the two +// acceptance paths agree and the index carve-out this claim used to pin as a declared residual is +// deleted (gunbc.recurring_failure_mode list_index_typed_optional_but_realized_as_the_bare_element). +// The red is the declared return and the record-literal field; the positive control is the same +// read eliminated by a match, which the Rust emitter must realize as a compilable program. +fn oar_index_negative_source() -> String { + "module oar.index_negative\n\nimport std.types { Int, String }\n\ntype Code { code: Int }\n\nfn probe(xs: List) -> Int {\n xs[0]\n}\n\nfn probe_field(xs: List) -> Code {\n Code { code: xs[0] }\n}\n" +} + +fn oar_index_positive_source() -> String { + "module oar.index_positive\n\nimport std.types { Int, String }\n\ntype Code { code: Int }\n\nfn probe(xs: List) -> Int {\n match xs[0] {\n Present { value: v } => v\n Absent => 0\n }\n}\n\nfn probe_field(xs: List) -> Code? {\n match xs[0] {\n Present { value: v } => Present { value: Code { code: v } }\n Absent => none\n }\n}\n" +} + +test fn an_index_access_at_a_required_position_refuses() -> Bool { + not_inhabited_blocking_count(source: oar_index_negative_source()) >= 2 +} + +test fn an_index_access_eliminated_by_a_match_compiles_as_rust() -> Bool { + not_inhabited_blocking_count(source: oar_index_positive_source()) == 0 + && compile_dag_rust_emit_check( + oar_index_positive_source(), + "src/oar_index_positive.rs", + [], + [] + ) } diff --git a/src/v1/01_tokenize.dag b/src/v1/01_tokenize.dag index e0c417a8c6b..a9d09e0c5db 100644 --- a/src/v1/01_tokenize.dag +++ b/src/v1/01_tokenize.dag @@ -92,15 +92,31 @@ fn make_token(text: String, span: SourceSpan, shape: TokenShape) -> Token { Token { text: text, span: span, shape: shape } } -fn source_char(source: SourceRef, pos: Int) -> String { - from_code_point(cp: source.source_chars[pos]) -} - -fn source_code_point(source: SourceRef, pos: Int) -> Int { +// A source position past either end has no code point, so the accessor answers `Int?` exactly as +// `xs[i]` is typed (v1.compiler.infer_access check_index_access_node) and realized (the Rust +// list_index is `.get(i).cloned()`). Each consumer says what an absent code point means where it +// reads one; there is no fabricated sentinel and no unwrap. +fn source_code_point(source: SourceRef, pos: Int) -> Int? { let _ = record_source_chars_index_lookup() source.source_chars[pos] } +// Whether the code point read is `want`. An absent code point is no character, so it is not `want`: +// that is the predicate's own answer, not a default standing in for one. +fn code_point_is(cp: Int?, want: Int) -> Bool { + match cp { + Present { value: c } => c == want + Absent => false + } +} + +fn code_point_satisfies(cp: Int?, pred: fn(Int) -> Bool) -> Bool { + match cp { + Present { value: c } => pred(c) + Absent => false + } +} + fn source_len(source: SourceRef) -> Int { count(source.source_chars) } @@ -110,25 +126,27 @@ fn source_substring(source: SourceRef, start: Int, end: Int) -> String { } fn source_scan_while(source: SourceRef, start: Int, pred: fn(Int) -> Bool) -> Int { - if start >= source_len(source: source) { source_len(source: source) } - else if pred(source.source_chars[start]) { - source_scan_while(source: source, start: start + 1, pred: pred) - } else { start } + match source.source_chars[start] { + Present { value: ch } => + if pred(ch) { source_scan_while(source: source, start: start + 1, pred: pred) } else { start } + Absent => source_len(source: source) + } } fn source_skip_ws(source: SourceRef, start: Int) -> Int { - if start >= source_len(source: source) { start } - else { - let ch = source.source_chars[start] - if ch == 32 || ch == 9 { source_skip_ws(source: source, start: start + 1) } - else { start } + match source.source_chars[start] { + Present { value: ch } => + if ch == 32 || ch == 9 { source_skip_ws(source: source, start: start + 1) } else { start } + Absent => start } } fn source_scan_to_eol(source: SourceRef, start: Int) -> Int { - if start >= source_len(source: source) { source_len(source: source) } - else if source.source_chars[start] == 10 { start } - else { source_scan_to_eol(source: source, start: start + 1) } + match source.source_chars[start] { + Present { value: ch } => + if ch == 10 { start } else { source_scan_to_eol(source: source, start: start + 1) } + Absent => source_len(source: source) + } } fn tokenize_artifact(source: String, file: String, env: ParseEnvironment) -> V1LexArtifact { @@ -156,7 +174,7 @@ The backward walk stops at the previous line feed, so it costs one line, not one fn source_line_start(source: SourceRef, pos: Int) -> Int { if pos <= 0 { 0 - } else if source_code_point(source: source, pos: pos - 1) == 10 { + } else if code_point_is(cp: source_code_point(source: source, pos: pos - 1), want: 10) { pos } else { source_line_start(source: source, pos: pos - 1) @@ -196,7 +214,7 @@ fn tokenize_line_first_content_pos(source: SourceRef, pos: Int, end: Int) -> Int end } else { let ch = source_code_point(source: source, pos: pos) - if ch == 32 || ch == 9 { + if code_point_is(cp: ch, want: 32) || code_point_is(cp: ch, want: 9) { tokenize_line_first_content_pos(source: source, pos: pos + 1, end: end) } else { pos @@ -213,8 +231,8 @@ fn preceded_by_annotation_line(source: SourceRef, pos: Int) -> Bool { let prev_end = line_start - 1 let content = tokenize_line_first_content_pos(source: source, pos: prev_start, end: prev_end) content + 1 < prev_end - && source_code_point(source: source, pos: content) == 47 - && source_code_point(source: source, pos: content + 1) == 47 + && code_point_is(cp: source_code_point(source: source, pos: content), want: 47) + && code_point_is(cp: source_code_point(source: source, pos: content + 1), want: 47) } } @@ -225,9 +243,7 @@ fn line_prefix_is_indent_only(source: SourceRef, pos: Int) -> Bool { ) } -fn scan_next_token(source: SourceRef, pos: TokPos, env: ParseEnvironment) -> ScanStep { - let ch = source_code_point(source: source, pos: pos.pos) - +fn scan_next_token(source: SourceRef, pos: TokPos, ch: Int, env: ParseEnvironment) -> ScanStep { if ch == 10 { return ScannedToken { result: ScanResult { pos: pos.pos + 1, @@ -236,10 +252,7 @@ fn scan_next_token(source: SourceRef, pos: TokPos, env: ParseEnvironment) -> Sca } } } - let next_ch_for_comment = if pos.pos + 1 < source_len(source: source) { - source_code_point(source: source, pos: pos.pos + 1) - } else { 0 } - if ch == 47 && next_ch_for_comment == 47 { + if ch == 47 && code_point_is(cp: source_code_point(source: source, pos: pos.pos + 1), want: 47) { let eol = source_scan_to_eol(source: source, start: pos.pos) return ScannedAnnotation { pos: eol, @@ -274,14 +287,15 @@ fn scan_next_token(source: SourceRef, pos: TokPos, env: ParseEnvironment) -> Sca fn tokenize_loop(source: SourceRef, tokens: List, annotations: List, pos: TokPos, fuel: Int, env: ParseEnvironment) -> TokenizerState { let s = skip_spaces(source: source, pos: pos) - if s.pos >= source_len(source: source) { - return TokenizerState { pos: s.pos, tokens: tokens, annotations: annotations, interp_depth: s.interp_depth } - } - match scan_next_token(source: source, pos: s, env: env) { - ScannedAnnotation { pos: next_pos, capture: capture, interp_depth: depth } => - tokenize_loop(source: source, tokens: tokens, annotations: list_push(annotations, capture), pos: TokPos { pos: next_pos, interp_depth: depth }, fuel: fuel - 1, env: env) - ScannedToken { result: result } => - tokenize_loop(source: source, tokens: list_push(tokens, result.token), annotations: annotations, pos: TokPos { pos: result.pos, interp_depth: result.interp_depth }, fuel: fuel - 1, env: env) + match source_code_point(source: source, pos: s.pos) { + Absent => TokenizerState { pos: s.pos, tokens: tokens, annotations: annotations, interp_depth: s.interp_depth } + Present { value: ch } => + match scan_next_token(source: source, pos: s, ch: ch, env: env) { + ScannedAnnotation { pos: next_pos, capture: capture, interp_depth: depth } => + tokenize_loop(source: source, tokens: tokens, annotations: list_push(annotations, capture), pos: TokPos { pos: next_pos, interp_depth: depth }, fuel: fuel - 1, env: env) + ScannedToken { result: result } => + tokenize_loop(source: source, tokens: list_push(tokens, result.token), annotations: annotations, pos: TokPos { pos: result.pos, interp_depth: result.interp_depth }, fuel: fuel - 1, env: env) + } } } @@ -290,22 +304,20 @@ fn scan_token(source: SourceRef, pos: TokPos, ch: Int, env: ParseEnvironment) -> if is_digit(ch: ch) { return scan_number(source: source, pos: pos) } if is_ident_start(ch: ch) { return scan_ident(source: source, pos: pos, env: env) } - let next_ch = if pos.pos + 1 < source_len(source: source) { - source_code_point(source: source, pos: pos.pos + 1) - } else { 0 } - - if ch == 61 && next_ch == 62 { return emit(pos: pos, shape: ShFatArrow, text: "=>", len: 2, file: source.file) } - if ch == 45 && next_ch == 62 { return emit(pos: pos, shape: ShArrow, text: "->", len: 2, file: source.file) } - if ch == 61 && next_ch == 61 { return emit(pos: pos, shape: ShEqEq, text: "==", len: 2, file: source.file) } - if ch == 33 && next_ch == 61 { return emit(pos: pos, shape: ShNe, text: "!=", len: 2, file: source.file) } - if ch == 60 && next_ch == 61 { return emit(pos: pos, shape: ShLe, text: "<=", len: 2, file: source.file) } - if ch == 62 && next_ch == 61 { return emit(pos: pos, shape: ShGe, text: ">=", len: 2, file: source.file) } - if ch == 38 && next_ch == 38 { return emit(pos: pos, shape: ShAnd, text: "&&", len: 2, file: source.file) } - if ch == 124 && next_ch == 124 { return emit(pos: pos, shape: ShOr, text: "||", len: 2, file: source.file) } - if ch == 124 && next_ch == 62 { return emit(pos: pos, shape: ShPipeArrow, text: "|>", len: 2, file: source.file) } + let next_ch = source_code_point(source: source, pos: pos.pos + 1) + + if ch == 61 && code_point_is(cp: next_ch, want: 62) { return emit(pos: pos, shape: ShFatArrow, text: "=>", len: 2, file: source.file) } + if ch == 45 && code_point_is(cp: next_ch, want: 62) { return emit(pos: pos, shape: ShArrow, text: "->", len: 2, file: source.file) } + if ch == 61 && code_point_is(cp: next_ch, want: 61) { return emit(pos: pos, shape: ShEqEq, text: "==", len: 2, file: source.file) } + if ch == 33 && code_point_is(cp: next_ch, want: 61) { return emit(pos: pos, shape: ShNe, text: "!=", len: 2, file: source.file) } + if ch == 60 && code_point_is(cp: next_ch, want: 61) { return emit(pos: pos, shape: ShLe, text: "<=", len: 2, file: source.file) } + if ch == 62 && code_point_is(cp: next_ch, want: 61) { return emit(pos: pos, shape: ShGe, text: ">=", len: 2, file: source.file) } + if ch == 38 && code_point_is(cp: next_ch, want: 38) { return emit(pos: pos, shape: ShAnd, text: "&&", len: 2, file: source.file) } + if ch == 124 && code_point_is(cp: next_ch, want: 124) { return emit(pos: pos, shape: ShOr, text: "||", len: 2, file: source.file) } + if ch == 124 && code_point_is(cp: next_ch, want: 62) { return emit(pos: pos, shape: ShPipeArrow, text: "|>", len: 2, file: source.file) } if ch == 124 { return emit(pos: pos, shape: ShPipe, text: "|", len: 1, file: source.file) } - if ch == 63 && next_ch == 63 { return emit(pos: pos, shape: ShNullCoalesce, text: "??", len: 2, file: source.file) } - if ch == 46 && next_ch == 46 { return emit(pos: pos, shape: ShDotDot, text: "..", len: 2, file: source.file) } + if ch == 63 && code_point_is(cp: next_ch, want: 63) { return emit(pos: pos, shape: ShNullCoalesce, text: "??", len: 2, file: source.file) } + if ch == 46 && code_point_is(cp: next_ch, want: 46) { return emit(pos: pos, shape: ShDotDot, text: "..", len: 2, file: source.file) } if ch == 61 { return emit(pos: pos, shape: ShEq, text: "=", len: 1, file: source.file) } if ch == 60 { return emit(pos: pos, shape: ShLt, text: "<", len: 1, file: source.file) } @@ -333,7 +345,7 @@ fn scan_token(source: SourceRef, pos: TokPos, ch: Int, env: ParseEnvironment) -> } } - let ch_text = source_char(source: source, pos: pos.pos) + let ch_text = from_code_point(cp: ch) match lookup(single_punct, key: ch_text) { Present { value: sh } => emit(pos: pos, shape: sh, text: ch_text, len: 1, file: source.file) Absent => emit(pos: pos, shape: ShUnknown, text: ch_text, len: 1, file: source.file) @@ -361,7 +373,7 @@ fn scan_ident(source: SourceRef, pos: TokPos, env: ParseEnvironment) -> ScanResu fn scan_number(source: SourceRef, pos: TokPos) -> ScanResult { let int_end = source_scan_while(source: source, start: pos.pos, pred: is_digit) - if int_end + 1 < source_len(source: source) && source_code_point(source: source, pos: int_end) == 46 && is_digit(ch: source_code_point(source: source, pos: int_end + 1)) { + if code_point_is(cp: source_code_point(source: source, pos: int_end), want: 46) && code_point_satisfies(cp: source_code_point(source: source, pos: int_end + 1), pred: is_digit) { let frac_end = source_scan_while(source: source, start: int_end + 1, pred: is_digit) let text = source_substring(source: source, start: pos.pos, end: frac_end) let token = make_token(text: text, span: make_file_span(file: source.file, start: pos.pos, end: frac_end), shape: ShLitFloat) @@ -486,16 +498,19 @@ fn scan_str_cont(source: SourceRef, pos: TokPos, span_start: Int) -> ScanResult } fn scan_string_body(source: SourceRef, pos: Int, acc: List) -> StringScanResult { - if pos >= source_len(source: source) { - UnterminatedString { content: acc, end_pos: pos } - } else { - let ch = source.source_chars[pos] - if ch == 34 { - ClosedString { content: acc, end_pos: pos } - } else if ch == 92 { - if pos + 1 < source_len(source: source) { - let escaped = source.source_chars[pos + 1] - if escaped == 117 && pos + 2 < source_len(source: source) && source.source_chars[pos + 2] == 123 { + match source.source_chars[pos] { + Absent => UnterminatedString { content: acc, end_pos: pos } + Present { value: ch } => scan_string_body_at(source: source, pos: pos, ch: ch, acc: acc) + } +} + +fn scan_string_body_at(source: SourceRef, pos: Int, ch: Int, acc: List) -> StringScanResult { + if ch == 34 { + ClosedString { content: acc, end_pos: pos } + } else if ch == 92 { + match source.source_chars[pos + 1] { + Present { value: escaped } => + if escaped == 117 && code_point_is(cp: source.source_chars[pos + 2], want: 123) { scan_string_body( source: source, pos: pos + 3, @@ -504,27 +519,23 @@ fn scan_string_body(source: SourceRef, pos: Int, acc: List) -> StringScanRe } else { scan_string_body(source: source, pos: pos + 2, acc: list_push(list_push(acc, 92), escaped)) } - } else { - UnterminatedString { content: list_push(acc, 92), end_pos: pos + 1 } - } - } else if ch == 123 { - if should_start_interpolation(source: source, pos: pos) { - InterpolationStart { content: acc, end_pos: pos } - } else { - scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, 123)) - } + Absent => UnterminatedString { content: list_push(acc, 92), end_pos: pos + 1 } + } + } else if ch == 123 { + if should_start_interpolation(source: source, pos: pos) { + InterpolationStart { content: acc, end_pos: pos } } else { - scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, ch)) + scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, 123)) } + } else { + scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, ch)) } } fn should_start_interpolation(source: SourceRef, pos: Int) -> Bool { - if pos + 1 >= source_len(source: source) { - false - } else { - let next = source_code_point(source: source, pos: pos + 1) - is_ident_start(ch: next) || next == 40 || next == 33 || next == 45 + match source_code_point(source: source, pos: pos + 1) { + Present { value: next } => is_ident_start(ch: next) || next == 40 || next == 33 || next == 45 + Absent => false } } @@ -532,27 +543,8 @@ fn process_escapes(chars: List) -> EscapeProcessResult { process_escapes_loop(source: chars, pos: 0, acc: []) } -// Why this accessor exists rather than indexing inline. `04_access.check_index_access_node` types a -// list index as OPTIONAL (`with_optional_cardinality`) — an out-of-range index has no value — but -// the Rust realization of an index is a bare element that panics out of range. The two disagree, so -// wherever the emitter acts on the declared type it emits a coercion the realization cannot -// satisfy: passing `chars[i]` straight to a declared fn parameter emits `.expect(...)` on an `i64` -// (E0599). Untouched positions — a let binding, a comparison, arithmetic, a builtin call — happen -// to line up, which is why the corpus has exactly one prior index-as-argument site and it calls the -// BUILTIN `from_code_point`. This accessor is the same shape as `source_code_point` and -// `source_char` above: a declared `-> Int` return is what carries the value across a fn boundary. -// It works because return position is not checked against the body (recorded on the finalization -// carrier, #7481), so it is borrowed load-bearing behavior, not a guarantee. Dissolves together -// with those two when the index model and its realization are reconciled — either the index -// realizes as an Option or it types as the element — at which point return-position typechecking -// would red all three at once. - -fn code_point_at(chars: List, pos: Int) -> Int { - chars[pos] -} - // The escape table below is written in code points because the whole tokenizer is: scan_token -// compares `ch == 61 && next_ch == 62` for `=>`, source_scan_to_eol compares `== 10`. The decimal +// compares `ch == 61 && code_point_is(cp: next_ch, want: 62)` for `=>`, source_scan_to_eol compares `== 10`. The decimal // literals here are the same alphabet: 34 double-quote, 48 `0`, 92 backslash, 110 `n`, 114 `r`, 116 // `t`, 117 `u`, 120 `x`, 123 open-brace, 125 close-brace; the values they resolve TO include 0 NUL, // 10 line-feed, 13 carriage-return, and 9 tab. This function used to compare one-character Strings @@ -618,82 +610,90 @@ fn unicode_escape_at( digit_count: Int, value: Int ) -> UnicodeEscape? { - if pos >= count(source) { - none - } else { - let ch = code_point_at(chars: source, pos: pos) - if ch == 125 { - if digit_count > 0 && unicode_scalar(code_point: value) { - Present { value: UnicodeEscape { code_point: value, next_pos: pos + 1 } } - } else { + match source[pos] { + Absent => none + Present { value: ch } => + if ch == 125 { + if digit_count > 0 && unicode_scalar(code_point: value) { + Present { value: UnicodeEscape { code_point: value, next_pos: pos + 1 } } + } else { + none + } + } else if digit_count >= 6 { none + } else { + match hex_digit_value(cp: ch) { + Present { value: digit } => unicode_escape_at( + source: source, + pos: pos + 1, + digit_count: digit_count + 1, + value: value * 16 + digit + ) + Absent => none + } } - } else if digit_count >= 6 { - none - } else { - match hex_digit_value(cp: ch) { - Present { value: digit } => unicode_escape_at( - source: source, - pos: pos + 1, - digit_count: digit_count + 1, - value: value * 16 + digit - ) - Absent => none - } - } } } fn process_escapes_loop(source: List, pos: Int, acc: List) -> EscapeProcessResult { - if pos >= count(source) { - EscapesProcessed { text: chars_to_string(chars: acc, start: 0, end: count(acc)) } - } else { - let ch = code_point_at(chars: source, pos: pos) - if ch == 92 { - if pos + 1 >= count(source) { - EscapeProcessingRefused {} + match source[pos] { + Absent => EscapesProcessed { text: chars_to_string(chars: acc, start: 0, end: count(acc)) } + Present { value: ch } => + if ch == 92 { + match source[pos + 1] { + Absent => EscapeProcessingRefused {} + Present { value: next } => process_escape_after_backslash(source: source, pos: pos, next: next, acc: acc) + } } else { - let next = code_point_at(chars: source, pos: pos + 1) - if next == 120 && pos + 3 < count(source) { - let hi = code_point_at(chars: source, pos: pos + 2) - let lo = code_point_at(chars: source, pos: pos + 3) - match hex_escape_char(hi: hi, lo: lo) { - Present { value: decoded } => - process_escapes_loop(source: source, pos: pos + 4, acc: list_push(acc, decoded)) - Absent => EscapeProcessingRefused {} - } - } else if next == 117 && pos + 2 < count(source) && code_point_at(chars: source, pos: pos + 2) == 123 { - match unicode_escape_at(source: source, pos: pos + 3, digit_count: 0, value: 0) { - Present { value: decoded } => process_escapes_loop( - source: source, - pos: decoded.next_pos, - acc: list_push(acc, decoded.code_point) - ) - Absent => EscapeProcessingRefused {} - } - } else { - let decoded = if next == 34 { Present { value: 34 } } - else if next == 48 { Present { value: 0 } } - else if next == 92 { Present { value: 92 } } - else if next == 110 { Present { value: 10 } } - else if next == 114 { Present { value: 13 } } - else if next == 116 { Present { value: 9 } } - else if next == 123 { Present { value: 123 } } - else if next == 125 { Present { value: 125 } } - else { none } - match decoded { - Present { value: code_point } => process_escapes_loop( - source: source, - pos: pos + 2, - acc: list_push(acc, code_point) - ) - Absent => EscapeProcessingRefused {} - } + process_escapes_loop(source: source, pos: pos + 1, acc: list_push(acc, ch)) + } + } +} + +fn process_escape_after_backslash(source: List, pos: Int, next: Int, acc: List) -> EscapeProcessResult { + if next == 120 { + match source[pos + 2] { + Present { value: hi } => match source[pos + 3] { + Present { value: lo } => match hex_escape_char(hi: hi, lo: lo) { + Present { value: decoded } => + process_escapes_loop(source: source, pos: pos + 4, acc: list_push(acc, decoded)) + Absent => EscapeProcessingRefused {} } + Absent => process_simple_escape(source: source, pos: pos, next: next, acc: acc) } - } else { - process_escapes_loop(source: source, pos: pos + 1, acc: list_push(acc, ch)) + Absent => process_simple_escape(source: source, pos: pos, next: next, acc: acc) } + } else if next == 117 && code_point_is(cp: source[pos + 2], want: 123) { + match unicode_escape_at(source: source, pos: pos + 3, digit_count: 0, value: 0) { + Present { value: decoded } => process_escapes_loop( + source: source, + pos: decoded.next_pos, + acc: list_push(acc, decoded.code_point) + ) + Absent => EscapeProcessingRefused {} + } + } else { + process_simple_escape(source: source, pos: pos, next: next, acc: acc) + } +} + +fn process_simple_escape(source: List, pos: Int, next: Int, acc: List) -> EscapeProcessResult { + let decoded = if next == 34 { Present { value: 34 } } + else if next == 48 { Present { value: 0 } } + else if next == 92 { Present { value: 92 } } + else if next == 110 { Present { value: 10 } } + else if next == 114 { Present { value: 13 } } + else if next == 116 { Present { value: 9 } } + else if next == 123 { Present { value: 123 } } + else if next == 125 { Present { value: 125 } } + else { none } + match decoded { + Present { value: code_point } => process_escapes_loop( + source: source, + pos: pos + 2, + acc: list_push(acc, code_point) + ) + Absent => EscapeProcessingRefused {} } } diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 1ef8d0f0f3b..e81cc7f3bf1 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -1402,7 +1402,6 @@ fn explicit_return_conformance_diags(declared: Node, body_typed: Node, scope: In subject: "", declared: declared, produced: expression_value_type(e: returned), - produced_by: returned, span: returned.span, scope: scope)) } @@ -1576,24 +1575,23 @@ fn declared_type_kernel_inhabitance_mismatch_here_or_at_element( // alias or brand between the two, and these positions carry no unfold (only a call argument // does, v1.compiler.infer host_text_unfolded_at_code_point_boundary). gunbc.rung_drop // text_boundary_identity_wall. -fn declared_type_conformance_diags(position: DeclaredTypePosition, subject: String, declared: Node, produced: Node, produced_by: Node, span: SourceSpan, scope: InferScope) -> List { +fn declared_type_conformance_diags(position: DeclaredTypePosition, subject: String, declared: Node, produced: Node, span: SourceSpan, scope: InferScope) -> List { concat( text_unjudged_advisories( a: text_representation_by_identity(n: declared, env: scope.type_env), b: text_representation_by_identity(n: produced, env: scope.type_env), position: "a declared type", span: span, module_name: scope.module_name), - declared_type_conformance_diags_core(position: position, subject: subject, declared: declared, produced: produced, produced_by: produced_by, span: span, scope: scope)) + declared_type_conformance_diags_core(position: position, subject: subject, declared: declared, produced: produced, span: span, scope: scope)) } -fn declared_type_conformance_diags_core(position: DeclaredTypePosition, subject: String, declared: Node, produced: Node, produced_by: Node, span: SourceSpan, scope: InferScope) -> List { +fn declared_type_conformance_diags_core(position: DeclaredTypePosition, subject: String, declared: Node, produced: Node, span: SourceSpan, scope: InferScope) -> List { let si = scope.type_env.source_indices let both_ground = conformance_ground_type(n: declared, source_indices: si) && conformance_ground_type(n: produced, source_indices: si) - let cardinality_diags = optional_at_required_value_obligation_diags( + let cardinality_diags = optional_at_required_obligation_diags( obligation: DeclaredTypeObligation { position: position, subject: subject, declared: declared, produced: produced, span: span }, - produced_by: produced_by, scope: scope) if (cardinality_diags |> count) > 0 { cardinality_diags } else if text_crossing_by_identity(left: declared, right: produced, env: scope.type_env) { @@ -4358,41 +4356,6 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: // relation also asked of branch pairs and of the lift direction, and optional-into-required is a // DIRECTED fact about a declared position, which is what the obligation carries. // -// AN INDEX ACCESS IS NOT JUDGED HERE, AND THAT IS A DECLARED RESIDUAL. v1.compiler.infer_access -// check_index_access_node types `xs[i]` as optional, while the Rust realization of an index is the -// bare element: the type and the realization disagree about the very fact this verdict reads, so -// the optionality of an index value is not established across the two acceptance paths. The seed -// itself stands on that disagreement -- v1.tokenize source_code_point and code_point_at return -// `chars[pos]` at a declared `-> Int`, and the note on code_point_at says return-position checking -// would red them. It did: the second-generation regeneration refused on exactly those two sites. -// Eliminating the optional with a match there would author an elimination the Rust realization -// cannot satisfy, so the repair is the reconciliation that note names (the index realizes as an -// optional, or types as the element), not a rewrite of its consumers. Until then a value whose -// tail expression is an index access produces no cardinality obligation at these four positions. -// The direct-call argument and list-element positions are untouched by this: they run the whole -// relation and keep whatever they decided before. -fn expr_value_is_index_access(e: Node) -> Bool { - match e.expr_data { - ExprIndex => true - ExprLet => - match let_body(texpr: e) { - Present { value: body } => expr_value_is_index_access(e: body) - Absent => false - } - ExprBlock => - match e.children |> last { - Present { value: tail } => expr_value_is_index_access(e: tail) - Absent => false - } - _ => false - } -} - -fn optional_at_required_value_obligation_diags(obligation: DeclaredTypeObligation, produced_by: Node, scope: InferScope) -> List { - if expr_value_is_index_access(e: produced_by) { [] } - else { optional_at_required_obligation_diags(obligation: obligation, scope: scope) } -} - fn optional_at_required_obligation_diags(obligation: DeclaredTypeObligation, scope: InferScope) -> List { if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) { [make_error_node( @@ -9302,7 +9265,6 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu subject: let_name, declared: declared, produced: produced_value_type, - produced_by: val_typed, span: val_expr.span, scope: scope) if (conformance |> count) > 0 { conformance } @@ -10714,7 +10676,7 @@ fn infer_record_lit_structural(occurrence_identity: NodeOccurrenceIdentity, type let field_cardinality_diags = if direct_call_formal_has_unbound_type_variable(n: field_conformance_type) { [] } else { - optional_at_required_value_obligation_diags( + optional_at_required_obligation_diags( obligation: DeclaredTypeObligation { position: PositionRecordLiteralField, subject: fi_name, @@ -10722,7 +10684,6 @@ fn infer_record_lit_structural(occurrence_identity: NodeOccurrenceIdentity, type produced: got_node, span: ar_typed.span }, - produced_by: ar_typed, scope: scope) } if direct_call_formal_has_unbound_type_variable(n: field_conformance_type) { @@ -13387,7 +13348,7 @@ fn infer_item(item: Node, scope: InferScope) -> TypedItemResult { let inferred_ret = if item.inferred != none { item.inferred } else { body_typed.inferred } let return_conformance_diags = if item.inferred != none { concat( - declared_type_conformance_diags(position: PositionDeclaredReturn, subject: "", declared: declared_return_type_node(item: item), produced: resolved_type(n: body_typed), produced_by: body_typed, span: item.body.value.span, scope: scope), + declared_type_conformance_diags(position: PositionDeclaredReturn, subject: "", declared: declared_return_type_node(item: item), produced: resolved_type(n: body_typed), span: item.body.value.span, scope: scope), explicit_return_conformance_diags(declared: declared_return_type_node(item: item), body_typed: body_typed, scope: scope)) } else { [] } @@ -13415,7 +13376,7 @@ fn infer_item(item: Node, scope: InferScope) -> TypedItemResult { let val_diags = if item.type_annotation != none { concat( val_result.diagnostics, - declared_type_conformance_diags(position: PositionDataInitializer, subject: "", declared: item.type_annotation.value, produced: expression_value_type(e: val_typed), produced_by: val_typed, span: item.body.value.span, scope: scope) + declared_type_conformance_diags(position: PositionDataInitializer, subject: "", declared: item.type_annotation.value, produced: expression_value_type(e: val_typed), span: item.body.value.span, scope: scope) ) } else { val_result.diagnostics } let inferred_ret = if item.type_annotation != none { Present { value: Resolved { node: item.type_annotation.value } } } else { val_typed.inferred } diff --git a/src/v1/languages.dag b/src/v1/languages.dag index df62e47277d..914b414de37 100644 --- a/src/v1/languages.dag +++ b/src/v1/languages.dag @@ -407,7 +407,7 @@ fn rust_spec() -> LanguageSpec { borrow_arg_template: "&{0}" }, indexing: IndexingSemantics { - list_index: "{0}[({1}) as usize].clone()", + list_index: "({0}).get(({1}) as usize).cloned()", map_index: "({0}).get(&{1}).cloned()", string_index: "v1_rt::char_at(&{0}, {1})", list_slice: "Rc::new((*{0})[{1} as usize..{2} as usize].to_vec())", @@ -857,7 +857,7 @@ fn dag_spec() -> LanguageSpec { borrow_arg_template: "&{0}" }, indexing: IndexingSemantics { - list_index: "{0}[({1}) as usize].clone()", + list_index: "({0}).get(({1}) as usize).cloned()", map_index: "({0}).get(&{1}).cloned()", string_index: "v1_rt::char_at(&{0}, {1})", list_slice: "Rc::new((*{0})[{1} as usize..{2} as usize].to_vec())", From d3edf7130d824bedc18824d1efc5240917495137 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 02:16:27 +0000 Subject: [PATCH 09/69] G: restore a data annotation's authored ? at resolve, not in the emitter resolve_node replaces a leaf type with its resolved declaration, whose cardinality is Required, so data d: NonEmptyStr? reached every later stage as NonEmptyStr. The item-annotation resolution now rebuilds through preserve_outer_optional_cardinality. Reverts the emitter-side no-op. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/04_resolve.dag | 2 +- src/v1/05_emit_rust.dag | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/v1/04_resolve.dag b/src/v1/04_resolve.dag index 7d9352925f0..cb6e8efe317 100644 --- a/src/v1/04_resolve.dag +++ b/src/v1/04_resolve.dag @@ -1376,7 +1376,7 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemReso } else { resolve_node(n: item.type_annotation.value, env: env, module_name: module_name) } - let resolved_anno = if item.type_annotation == none { none } else { Present { value: anno_resolved.resolved } } + let resolved_anno = if item.type_annotation == none { none } else { Present { value: preserve_outer_optional_cardinality(outer: item.type_annotation.value, inner: anno_resolved.resolved) } } let anno_diags = anno_resolved.diagnostics let transport_resolved = if item.transport == none { diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 3ab73d8bd57..1ea1ac37481 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -41,7 +41,7 @@ import v1.std.core { Unmarked, Node, InferredNode, Resolved, CompilerError, TypeVariable, is_compiler_error, import_is_all, import_specific_names_at, module_imports, module_items, param_node_type_expr, param_node_default_value, authored_name_at, NewlineIndex, find_child_named, tuple_type_name, - qualified_last_segment, preserve_outer_optional_cardinality, expr_var_name_at, expr_call_func_at, field_access_field_at, + qualified_last_segment, expr_var_name_at, expr_call_func_at, field_access_field_at, param_node_name_at, resource_use_name_at, field_binding_name_at, field_node_name_at, field_node_type_expr, generic_param_name_at, ExprData, NoExprData, ExprLiteral, ExprElaboratedLiteral, ExprError, ExprVar, ExprFieldAccess, ExprCall, ExprMethodCall, ExprMatch, ExprIf, ExprLet, @@ -7532,7 +7532,7 @@ fn emit_typed_item(item: Node, module_name: String, registry: Map match item.body { Present { value: data_value } => { - emit_data_def(name: item_text, type_node: preserve_outer_optional_cardinality(outer: item, inner: data_anno), value: data_value, registry: registry, scope: scope, depth: 0, shared_types: shared_types, emit_info: emit_info) + emit_data_def(name: item_text, type_node: data_anno, value: data_value, registry: registry, scope: scope, depth: 0, shared_types: shared_types, emit_info: emit_info) } Absent => emit_rust_item_refusal(item_text: item_text, reason: "data item carries no value") } @@ -16711,11 +16711,6 @@ fn data_def_annotation_is_named_refinement(annotation: Node, source_indices: Map // declared type decided by the carrier and its wrap decided by the spelling, and needs_rc is // threaded into emit_data_def_body, so the value took the same answer as the signature. Routed to // the carrier authority; the spelling key is deleted rather than kept beside it. -// A DATA ROW'S DECLARED `?` LIVES ON THE ITEM, not on its annotation node (infer's -// declared_type_conformance_note class 4), so the ModuleItemDataValue caller hands this function the -// annotation rebuilt through preserve_outer_optional_cardinality -- the same authority fn returns use. -// Without it a branded `data d: NonEmptyStr? = Present { .. }` rendered `-> NonEmptyStr` here (the -// preserves_declared_brand arm renders from the annotation alone) and every consumer refused. fn emit_data_def(name: String, type_node: Node, value: Node, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { let annotation_type_node = type_node let ann_name = authored_name_at(source_indices: scope.type_env.source_indices, node: annotation_type_node) From 479e1e3b97ccc7e2ab0eedda27e4f533ec9471f5 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 02:47:41 +0000 Subject: [PATCH 10/69] G: the named-refinement arm of emit_data_def keeps the row's declared ? NonEmptyStr resolves to a where-refinement Conj (one base child), so it misses preserves_declared_brand and is rendered by the named-refinement arm, the one arm with no rust_carrier_optional_wrap. Reverts the resolve change: the param path shows resolve already keeps the ?. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/04_resolve.dag | 2 +- src/v1/05_emit_rust.dag | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/v1/04_resolve.dag b/src/v1/04_resolve.dag index cb6e8efe317..7d9352925f0 100644 --- a/src/v1/04_resolve.dag +++ b/src/v1/04_resolve.dag @@ -1376,7 +1376,7 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemReso } else { resolve_node(n: item.type_annotation.value, env: env, module_name: module_name) } - let resolved_anno = if item.type_annotation == none { none } else { Present { value: preserve_outer_optional_cardinality(outer: item.type_annotation.value, inner: anno_resolved.resolved) } } + let resolved_anno = if item.type_annotation == none { none } else { Present { value: anno_resolved.resolved } } let anno_diags = anno_resolved.diagnostics let transport_resolved = if item.transport == none { diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 11f17bd68c8..d8acfaddee3 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -16715,6 +16715,13 @@ fn data_def_annotation_is_named_refinement(annotation: Node, source_indices: Map // declared type decided by the carrier and its wrap decided by the spelling, and needs_rc is // threaded into emit_data_def_body, so the value took the same answer as the signature. Routed to // the carrier authority; the spelling key is deleted rather than kept beside it. +// A NAMED REFINEMENT ROW KEEPS ITS DECLARED `?`. A where-refinement such as std.types NonEmptyStr +// resolves to a Conj carrying its base as one child, so it fails preserves_declared_brand's +// childless test and is rendered by the named-refinement arm -- the one arm that rendered through +// coerce_primitive_type without rust_carrier_optional_wrap. gunbc.fleet_tailnet +// fleet_tailnet_domain (`NonEmptyStr? = Present { .. }`) was emitted `-> NonEmptyStr` and its +// consumer refused E0308. The control is gunbc.instruments.native_emission_controls +// optional_data_row_cases. fn emit_data_def(name: String, type_node: Node, value: Node, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { let annotation_type_node = type_node let ann_name = authored_name_at(source_indices: scope.type_env.source_indices, node: annotation_type_node) @@ -16732,7 +16739,7 @@ fn emit_data_def(name: String, type_node: Node, value: Node, registry: Map Date: Sun, 4 Oct 2026 02:48:43 +0000 Subject: [PATCH 11/69] tokenizer: keep string-body and escape scans single self-recursive functions so their tail calls lower to loops Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/01_tokenize.dag | 120 +++++++++++++++++++---------------------- 1 file changed, 54 insertions(+), 66 deletions(-) diff --git a/src/v1/01_tokenize.dag b/src/v1/01_tokenize.dag index a9d09e0c5db..ae7271844f7 100644 --- a/src/v1/01_tokenize.dag +++ b/src/v1/01_tokenize.dag @@ -500,35 +500,32 @@ fn scan_str_cont(source: SourceRef, pos: TokPos, span_start: Int) -> ScanResult fn scan_string_body(source: SourceRef, pos: Int, acc: List) -> StringScanResult { match source.source_chars[pos] { Absent => UnterminatedString { content: acc, end_pos: pos } - Present { value: ch } => scan_string_body_at(source: source, pos: pos, ch: ch, acc: acc) - } -} - -fn scan_string_body_at(source: SourceRef, pos: Int, ch: Int, acc: List) -> StringScanResult { - if ch == 34 { - ClosedString { content: acc, end_pos: pos } - } else if ch == 92 { - match source.source_chars[pos + 1] { - Present { value: escaped } => - if escaped == 117 && code_point_is(cp: source.source_chars[pos + 2], want: 123) { - scan_string_body( - source: source, - pos: pos + 3, - acc: list_push(list_push(list_push(acc, 92), 117), 123) - ) + Present { value: ch } => + if ch == 34 { + ClosedString { content: acc, end_pos: pos } + } else if ch == 92 { + match source.source_chars[pos + 1] { + Present { value: escaped } => + if escaped == 117 && code_point_is(cp: source.source_chars[pos + 2], want: 123) { + scan_string_body( + source: source, + pos: pos + 3, + acc: list_push(list_push(list_push(acc, 92), 117), 123) + ) + } else { + scan_string_body(source: source, pos: pos + 2, acc: list_push(list_push(acc, 92), escaped)) + } + Absent => UnterminatedString { content: list_push(acc, 92), end_pos: pos + 1 } + } + } else if ch == 123 { + if should_start_interpolation(source: source, pos: pos) { + InterpolationStart { content: acc, end_pos: pos } } else { - scan_string_body(source: source, pos: pos + 2, acc: list_push(list_push(acc, 92), escaped)) + scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, 123)) } - Absent => UnterminatedString { content: list_push(acc, 92), end_pos: pos + 1 } - } - } else if ch == 123 { - if should_start_interpolation(source: source, pos: pos) { - InterpolationStart { content: acc, end_pos: pos } - } else { - scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, 123)) - } - } else { - scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, ch)) + } else { + scan_string_body(source: source, pos: pos + 1, acc: list_push(acc, ch)) + } } } @@ -639,61 +636,52 @@ fn process_escapes_loop(source: List, pos: Int, acc: List) -> EscapePr match source[pos] { Absent => EscapesProcessed { text: chars_to_string(chars: acc, start: 0, end: count(acc)) } Present { value: ch } => - if ch == 92 { + if ch != 92 { + process_escapes_loop(source: source, pos: pos + 1, acc: list_push(acc, ch)) + } else { match source[pos + 1] { Absent => EscapeProcessingRefused {} - Present { value: next } => process_escape_after_backslash(source: source, pos: pos, next: next, acc: acc) + Present { value: next } => + match escape_decoding(source: source, pos: pos, next: next) { + Present { value: decoded } => process_escapes_loop(source: source, pos: decoded.next_pos, acc: list_push(acc, decoded.code_point)) + Absent => EscapeProcessingRefused {} + } } - } else { - process_escapes_loop(source: source, pos: pos + 1, acc: list_push(acc, ch)) } } } -fn process_escape_after_backslash(source: List, pos: Int, next: Int, acc: List) -> EscapeProcessResult { +// What the escape starting at the backslash `pos` decodes to and where scanning resumes; absent +// when the escape is malformed or truncated. Not recursive, so the loop above stays one +// self-recursive function and its tail call lowers to a loop. +fn escape_decoding(source: List, pos: Int, next: Int) -> UnicodeEscape? { if next == 120 { match source[pos + 2] { Present { value: hi } => match source[pos + 3] { Present { value: lo } => match hex_escape_char(hi: hi, lo: lo) { - Present { value: decoded } => - process_escapes_loop(source: source, pos: pos + 4, acc: list_push(acc, decoded)) - Absent => EscapeProcessingRefused {} + Present { value: decoded } => Present { value: UnicodeEscape { code_point: decoded, next_pos: pos + 4 } } + Absent => none } - Absent => process_simple_escape(source: source, pos: pos, next: next, acc: acc) + Absent => none } - Absent => process_simple_escape(source: source, pos: pos, next: next, acc: acc) + Absent => none } } else if next == 117 && code_point_is(cp: source[pos + 2], want: 123) { - match unicode_escape_at(source: source, pos: pos + 3, digit_count: 0, value: 0) { - Present { value: decoded } => process_escapes_loop( - source: source, - pos: decoded.next_pos, - acc: list_push(acc, decoded.code_point) - ) - Absent => EscapeProcessingRefused {} - } + unicode_escape_at(source: source, pos: pos + 3, digit_count: 0, value: 0) } else { - process_simple_escape(source: source, pos: pos, next: next, acc: acc) - } -} - -fn process_simple_escape(source: List, pos: Int, next: Int, acc: List) -> EscapeProcessResult { - let decoded = if next == 34 { Present { value: 34 } } - else if next == 48 { Present { value: 0 } } - else if next == 92 { Present { value: 92 } } - else if next == 110 { Present { value: 10 } } - else if next == 114 { Present { value: 13 } } - else if next == 116 { Present { value: 9 } } - else if next == 123 { Present { value: 123 } } - else if next == 125 { Present { value: 125 } } - else { none } - match decoded { - Present { value: code_point } => process_escapes_loop( - source: source, - pos: pos + 2, - acc: list_push(acc, code_point) - ) - Absent => EscapeProcessingRefused {} + let simple = if next == 34 { Present { value: 34 } } + else if next == 48 { Present { value: 0 } } + else if next == 92 { Present { value: 92 } } + else if next == 110 { Present { value: 10 } } + else if next == 114 { Present { value: 13 } } + else if next == 116 { Present { value: 9 } } + else if next == 123 { Present { value: 123 } } + else if next == 125 { Present { value: 125 } } + else { none } + match simple { + Present { value: code_point } => Present { value: UnicodeEscape { code_point: code_point, next_pos: pos + 2 } } + Absent => none + } } } From 60eefa00809aefba4ef54825c7ec94f17af1da9d Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 03:15:42 +0000 Subject: [PATCH 12/69] G: regenerated v1_compiler_emit_rust.rs Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index d4c9a0070cd..fd957e0cc80 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -38678,18 +38678,21 @@ pub fn emit_data_def( annotation_type_node.clone(), scope.type_env.clone().source_indices.clone(), ) { - crate::v1_compiler_coercion::coerce_primitive_type( - crate::v1_compiler_coercion::type_reference_realization( - annotation_type_node.clone(), + rust_carrier_optional_wrap( + annotation_type_node.clone(), + crate::v1_compiler_coercion::coerce_primitive_type( + crate::v1_compiler_coercion::type_reference_realization( + annotation_type_node.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + annotation_type_node.clone(), + ), + RenderTarget::Rust, + ), crate::v1_std_core::authored_name_at( scope.type_env.clone().source_indices.clone(), annotation_type_node.clone(), ), - RenderTarget::Rust, - ), - crate::v1_std_core::authored_name_at( - scope.type_env.clone().source_indices.clone(), - annotation_type_node.clone(), ), ) } else { From 2e264a7af6ce379339931dfa6834fc61c171dd87 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 03:17:57 +0000 Subject: [PATCH 13/69] stage0: regenerate infer, languages and tokenize mirrors (fixed point at third generation) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 61 +- src/v1/stage0/src/v1_compiler_languages.rs | 4 +- src/v1/stage0/src/v1_compiler_tokenize.rs | 686 +++++++++++---------- 3 files changed, 370 insertions(+), 381 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 029f18a7d97..bf1205a2c7f 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -1924,7 +1924,6 @@ pub fn explicit_return_conformance_diags( "".to_string(), declared.clone(), expression_value_type(returned.clone()), - returned.clone(), returned.span.clone(), scope.clone(), )) @@ -2147,7 +2146,6 @@ pub fn declared_type_conformance_diags( subject: String, declared: Rc, produced: Rc, - produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2170,7 +2168,6 @@ pub fn declared_type_conformance_diags( subject.clone(), declared.clone(), produced.clone(), - produced_by.clone(), span.clone(), scope.clone(), ), @@ -2182,7 +2179,6 @@ pub fn declared_type_conformance_diags_core( subject: String, declared: Rc, produced: Rc, - produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2190,7 +2186,7 @@ pub fn declared_type_conformance_diags_core( let si = scope.type_env.clone().source_indices.clone(); let both_ground = (conformance_ground_type(declared.clone(), si.clone()) && conformance_ground_type(produced.clone(), si.clone())); - let cardinality_diags = optional_at_required_value_obligation_diags( + let cardinality_diags = optional_at_required_obligation_diags( Rc::new(DeclaredTypeObligation { position: position.clone(), subject: subject.clone(), @@ -2198,7 +2194,6 @@ pub fn declared_type_conformance_diags_core( produced: produced.clone(), span: span.clone(), }), - produced_by.clone(), scope.clone(), ); if ((cardinality_diags.clone().len() as i64) > 0) { @@ -6158,53 +6153,6 @@ pub fn optional_produced_at_required_declared( } } -pub fn expr_value_is_index_access(mut __tco_loop_e: Rc) -> bool { - loop { - #[allow(unused_mut)] - let mut e = __tco_loop_e; - match (*e.expr_data.clone()).clone() { - ExprData::ExprIndex => { - break true; - } - ExprData::ExprLet => match crate::v1_std_core::let_body(e.clone()) { - Some(body) => { - let __tco_0 = body.clone(); - __tco_loop_e = __tco_0; - continue; - } - std::option::Option::None => { - break false; - } - }, - ExprData::ExprBlock => match e.children.clone().last().cloned() { - Some(tail) => { - let __tco_0 = tail.clone(); - __tco_loop_e = __tco_0; - continue; - } - std::option::Option::None => { - break false; - } - }, - _ => { - break false; - } - } - } -} - -pub fn optional_at_required_value_obligation_diags( - obligation: Rc, - produced_by: Rc, - scope: Rc, -) -> Rc>> { - if expr_value_is_index_access(produced_by.clone()) { - Rc::new(vec![]) - } else { - optional_at_required_obligation_diags(obligation.clone(), scope.clone()) - } -} - pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, @@ -14620,7 +14568,6 @@ crate::v1_compiler_infer_types::resolve_type_variables_from_template(t.clone(), let_name.clone(), declared.clone(), produced_value_type.clone(), - val_typed.clone(), val_expr.span.clone(), scope.clone(), ); @@ -17307,13 +17254,13 @@ let field_type_diags = match field_declared_type.clone() { let field_cardinality_diags = if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) } else { - optional_at_required_value_obligation_diags(Rc::new(DeclaredTypeObligation { + optional_at_required_obligation_diags(Rc::new(DeclaredTypeObligation { position: DeclaredTypePosition::PositionRecordLiteralField, subject: fi_name.clone(), declared: expected_node.clone(), produced: got_node.clone(), span: ar_typed.span.clone(), -}), ar_typed.clone(), scope.clone()) +}), scope.clone()) }; if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) @@ -22994,7 +22941,6 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), declared_return_type_node(item.clone()), crate::v1_compiler_infer_types::resolved_type(body_typed.clone()), - body_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), @@ -23102,7 +23048,6 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), item.type_annotation.clone().clone().unwrap(), expression_value_type(val_typed.clone()), - val_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), diff --git a/src/v1/stage0/src/v1_compiler_languages.rs b/src/v1/stage0/src/v1_compiler_languages.rs index 04c78919d63..a857a2d49bb 100644 --- a/src/v1/stage0/src/v1_compiler_languages.rs +++ b/src/v1/stage0/src/v1_compiler_languages.rs @@ -545,7 +545,7 @@ pub fn rust_spec() -> Rc { borrow_arg_template: "&{0}".to_string(), }), indexing: Rc::new(IndexingSemantics { - list_index: "{0}[({1}) as usize].clone()".to_string(), + list_index: "({0}).get(({1}) as usize).cloned()".to_string(), map_index: "({0}).get(&{1}).cloned()".to_string(), string_index: "v1_rt::char_at(&{0}, {1})".to_string(), list_slice: Some("Rc::new((*{0})[{1} as usize..{2} as usize].to_vec())".to_string()), @@ -1094,7 +1094,7 @@ pub fn dag_spec() -> Rc { borrow_arg_template: "&{0}".to_string(), }), indexing: Rc::new(IndexingSemantics { - list_index: "{0}[({1}) as usize].clone()".to_string(), + list_index: "({0}).get(({1}) as usize).cloned()".to_string(), map_index: "({0}).get(&{1}).cloned()".to_string(), string_index: "v1_rt::char_at(&{0}, {1})".to_string(), list_slice: Some("Rc::new((*{0})[{1} as usize..{2} as usize].to_vec())".to_string()), diff --git a/src/v1/stage0/src/v1_compiler_tokenize.rs b/src/v1/stage0/src/v1_compiler_tokenize.rs index 5898ce8fa0a..0fde8441e1e 100644 --- a/src/v1/stage0/src/v1_compiler_tokenize.rs +++ b/src/v1/stage0/src/v1_compiler_tokenize.rs @@ -116,14 +116,26 @@ pub fn make_token(text: String, span: Rc, shape: TokenShape) -> Rc, pos: i64) -> String { - v1_rt::from_code_point(source.source_chars.clone()[(pos.clone()) as usize].clone()) -} - -pub fn source_code_point(source: Rc, pos: i64) -> i64 { +pub fn source_code_point(source: Rc, pos: i64) -> Option { { let _ = v1_rt::record_source_chars_index_lookup(); - source.source_chars.clone()[(pos.clone()) as usize].clone() + (source.source_chars.clone()) + .get((pos.clone()) as usize) + .cloned() + } +} + +pub fn code_point_is(cp: Option, want: i64) -> bool { + match cp.clone() { + Some(c) => (c.clone() == want.clone()), + std::option::Option::None => false, + } +} + +pub fn code_point_satisfies(cp: Option, pred: impl Fn(i64) -> bool + Clone) -> bool { + match cp.clone() { + Some(c) => pred(c.clone()), + std::option::Option::None => false, } } @@ -147,21 +159,27 @@ pub fn source_scan_while( let mut start = __tco_loop_start; #[allow(unused_mut)] let mut pred = __tco_loop_pred; - if (start.clone() >= source_len(source.clone())) { - break source_len(source.clone()); - } else { - if pred(source.source_chars.clone()[(start.clone()) as usize].clone()) { - { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(start, 1); - let __tco_2 = pred; - __tco_loop_source = __tco_0; - __tco_loop_start = __tco_1; - __tco_loop_pred = __tco_2; - continue; + match (source.source_chars.clone()) + .get((start.clone()) as usize) + .cloned() + { + Some(ch) => { + if pred(ch.clone()) { + { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(start, 1); + let __tco_2 = pred; + __tco_loop_source = __tco_0; + __tco_loop_start = __tco_1; + __tco_loop_pred = __tco_2; + continue; + } + } else { + break start.clone(); } - } else { - break start.clone(); + } + std::option::Option::None => { + break source_len(source.clone()); } } } @@ -173,19 +191,24 @@ pub fn source_skip_ws(mut __tco_loop_source: Rc, mut __tco_loop_start let mut source = __tco_loop_source; #[allow(unused_mut)] let mut start = __tco_loop_start; - if (start.clone() >= source_len(source.clone())) { - break start.clone(); - } else { - let ch = source.source_chars.clone()[(start.clone()) as usize].clone(); - if ((ch.clone() == 32) || (ch.clone() == 9)) { - { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(start, 1); - __tco_loop_source = __tco_0; - __tco_loop_start = __tco_1; - continue; + match (source.source_chars.clone()) + .get((start.clone()) as usize) + .cloned() + { + Some(ch) => { + if ((ch.clone() == 32) || (ch.clone() == 9)) { + { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(start, 1); + __tco_loop_source = __tco_0; + __tco_loop_start = __tco_1; + continue; + } + } else { + break start.clone(); } - } else { + } + std::option::Option::None => { break start.clone(); } } @@ -198,20 +221,26 @@ pub fn source_scan_to_eol(mut __tco_loop_source: Rc, mut __tco_loop_s let mut source = __tco_loop_source; #[allow(unused_mut)] let mut start = __tco_loop_start; - if (start.clone() >= source_len(source.clone())) { - break source_len(source.clone()); - } else { - if (source.source_chars.clone()[(start.clone()) as usize].clone() == 10) { - break start.clone(); - } else { - { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(start, 1); - __tco_loop_source = __tco_0; - __tco_loop_start = __tco_1; - continue; + match (source.source_chars.clone()) + .get((start.clone()) as usize) + .cloned() + { + Some(ch) => { + if (ch.clone() == 10) { + break start.clone(); + } else { + { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(start, 1); + __tco_loop_source = __tco_0; + __tco_loop_start = __tco_1; + continue; + } } } + std::option::Option::None => { + break source_len(source.clone()); + } } } } @@ -279,7 +308,10 @@ pub fn source_line_start(mut __tco_loop_source: Rc, mut __tco_loop_po if (pos.clone() <= 0) { break 0; } else { - if (source_code_point(source.clone(), v1_rt::int_sub(pos.clone(), 1)) == 10) { + if code_point_is( + source_code_point(source.clone(), v1_rt::int_sub(pos.clone(), 1)), + 10, + ) { break pos.clone(); } else { { @@ -337,7 +369,7 @@ pub fn tokenize_line_first_content_pos( break end.clone(); } else { let ch = source_code_point(source.clone(), pos.clone()); - if ((ch.clone() == 32) || (ch.clone() == 9)) { + if (code_point_is(ch.clone(), 32) || code_point_is(ch.clone(), 9)) { { let __tco_0 = source; let __tco_1 = v1_rt::int_add(pos, 1); @@ -370,9 +402,11 @@ pub fn preceded_by_annotation_line(source: Rc, pos: i64) -> bool { prev_end.clone(), ); (((v1_rt::int_add(content.clone(), 1) < prev_end.clone()) - && (source_code_point(source.clone(), content.clone()) == 47)) - && (source_code_point(source.clone(), v1_rt::int_add(content.clone(), 1)) - == 47)) + && code_point_is(source_code_point(source.clone(), content.clone()), 47)) + && code_point_is( + source_code_point(source.clone(), v1_rt::int_add(content.clone(), 1)), + 47, + )) } } } @@ -392,10 +426,10 @@ pub fn line_prefix_is_indent_only(source: Rc, pos: i64) -> bool { pub fn scan_next_token( source: Rc, pos: Rc, + ch: i64, env: Rc, ) -> Rc { { - let ch = source_code_point(source.clone(), pos.pos.clone()); if (ch.clone() == 10) { return Rc::new(ScanStep::ScannedToken { result: Rc::new(ScanResult { @@ -413,13 +447,12 @@ pub fn scan_next_token( }), }); } - let next_ch_for_comment = - if (v1_rt::int_add(pos.pos.clone(), 1) < source_len(source.clone())) { - source_code_point(source.clone(), v1_rt::int_add(pos.pos.clone(), 1)) - } else { - 0 - }; - if ((ch.clone() == 47) && (next_ch_for_comment.clone() == 47)) { + if ((ch.clone() == 47) + && code_point_is( + source_code_point(source.clone(), v1_rt::int_add(pos.pos.clone(), 1)), + 47, + )) + { { let eol = source_scan_to_eol(source.clone(), pos.pos.clone()); return Rc::new(ScanStep::ScannedAnnotation { @@ -515,55 +548,60 @@ pub fn tokenize_loop( #[allow(unused_mut)] let mut env = __tco_loop_env; let s = skip_spaces(source.clone(), pos.clone()); - if (s.pos.clone() >= source_len(source.clone())) { - return Rc::new(TokenizerState { - pos: s.pos.clone(), - tokens: tokens.clone(), - annotations: annotations.clone(), - interp_depth: s.interp_depth.clone(), - }); - } - match (*scan_next_token(source.clone(), s.clone(), env.clone())).clone() { - ScanStep::ScannedAnnotation { - pos: next_pos, - capture, - interp_depth: depth, - .. - } => { - let __tco_0 = source; - let __tco_1 = tokens; - let __tco_2 = v1_rt::rc_list_push(annotations, capture.clone()); - let __tco_3 = Rc::new(TokPos { - pos: next_pos.clone(), - interp_depth: depth.clone(), + match source_code_point(source.clone(), s.pos.clone()) { + std::option::Option::None => { + break Rc::new(TokenizerState { + pos: s.pos.clone(), + tokens: tokens.clone(), + annotations: annotations.clone(), + interp_depth: s.interp_depth.clone(), }); - let __tco_4 = v1_rt::int_sub(fuel, 1); - let __tco_5 = env; - __tco_loop_source = __tco_0; - __tco_loop_tokens = __tco_1; - __tco_loop_annotations = __tco_2; - __tco_loop_pos = __tco_3; - __tco_loop_fuel = __tco_4; - __tco_loop_env = __tco_5; - continue; } - ScanStep::ScannedToken { result: result, .. } => { - let __tco_0 = source; - let __tco_1 = v1_rt::rc_list_push(tokens, result.token.clone()); - let __tco_2 = annotations; - let __tco_3 = Rc::new(TokPos { - pos: result.pos.clone(), - interp_depth: result.interp_depth.clone(), - }); - let __tco_4 = v1_rt::int_sub(fuel, 1); - let __tco_5 = env; - __tco_loop_source = __tco_0; - __tco_loop_tokens = __tco_1; - __tco_loop_annotations = __tco_2; - __tco_loop_pos = __tco_3; - __tco_loop_fuel = __tco_4; - __tco_loop_env = __tco_5; - continue; + Some(ch) => { + match (*scan_next_token(source.clone(), s.clone(), ch.clone(), env.clone())).clone() + { + ScanStep::ScannedAnnotation { + pos: next_pos, + capture, + interp_depth: depth, + .. + } => { + let __tco_0 = source; + let __tco_1 = tokens; + let __tco_2 = v1_rt::rc_list_push(annotations, capture.clone()); + let __tco_3 = Rc::new(TokPos { + pos: next_pos.clone(), + interp_depth: depth.clone(), + }); + let __tco_4 = v1_rt::int_sub(fuel, 1); + let __tco_5 = env; + __tco_loop_source = __tco_0; + __tco_loop_tokens = __tco_1; + __tco_loop_annotations = __tco_2; + __tco_loop_pos = __tco_3; + __tco_loop_fuel = __tco_4; + __tco_loop_env = __tco_5; + continue; + } + ScanStep::ScannedToken { result: result, .. } => { + let __tco_0 = source; + let __tco_1 = v1_rt::rc_list_push(tokens, result.token.clone()); + let __tco_2 = annotations; + let __tco_3 = Rc::new(TokPos { + pos: result.pos.clone(), + interp_depth: result.interp_depth.clone(), + }); + let __tco_4 = v1_rt::int_sub(fuel, 1); + let __tco_5 = env; + __tco_loop_source = __tco_0; + __tco_loop_tokens = __tco_1; + __tco_loop_annotations = __tco_2; + __tco_loop_pos = __tco_3; + __tco_loop_fuel = __tco_4; + __tco_loop_env = __tco_5; + continue; + } + } } } } @@ -585,12 +623,8 @@ pub fn scan_token( if is_ident_start(ch.clone()) { return scan_ident(source.clone(), pos.clone(), env.clone()); } - let next_ch = if (v1_rt::int_add(pos.pos.clone(), 1) < source_len(source.clone())) { - source_code_point(source.clone(), v1_rt::int_add(pos.pos.clone(), 1)) - } else { - 0 - }; - if ((ch.clone() == 61) && (next_ch.clone() == 62)) { + let next_ch = source_code_point(source.clone(), v1_rt::int_add(pos.pos.clone(), 1)); + if ((ch.clone() == 61) && code_point_is(next_ch.clone(), 62)) { return emit( pos.clone(), TokenShape::ShFatArrow, @@ -599,7 +633,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 45) && (next_ch.clone() == 62)) { + if ((ch.clone() == 45) && code_point_is(next_ch.clone(), 62)) { return emit( pos.clone(), TokenShape::ShArrow, @@ -608,7 +642,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 61) && (next_ch.clone() == 61)) { + if ((ch.clone() == 61) && code_point_is(next_ch.clone(), 61)) { return emit( pos.clone(), TokenShape::ShEqEq, @@ -617,7 +651,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 33) && (next_ch.clone() == 61)) { + if ((ch.clone() == 33) && code_point_is(next_ch.clone(), 61)) { return emit( pos.clone(), TokenShape::ShNe, @@ -626,7 +660,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 60) && (next_ch.clone() == 61)) { + if ((ch.clone() == 60) && code_point_is(next_ch.clone(), 61)) { return emit( pos.clone(), TokenShape::ShLe, @@ -635,7 +669,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 62) && (next_ch.clone() == 61)) { + if ((ch.clone() == 62) && code_point_is(next_ch.clone(), 61)) { return emit( pos.clone(), TokenShape::ShGe, @@ -644,7 +678,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 38) && (next_ch.clone() == 38)) { + if ((ch.clone() == 38) && code_point_is(next_ch.clone(), 38)) { return emit( pos.clone(), TokenShape::ShAnd, @@ -653,7 +687,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 124) && (next_ch.clone() == 124)) { + if ((ch.clone() == 124) && code_point_is(next_ch.clone(), 124)) { return emit( pos.clone(), TokenShape::ShOr, @@ -662,7 +696,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 124) && (next_ch.clone() == 62)) { + if ((ch.clone() == 124) && code_point_is(next_ch.clone(), 62)) { return emit( pos.clone(), TokenShape::ShPipeArrow, @@ -680,7 +714,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 63) && (next_ch.clone() == 63)) { + if ((ch.clone() == 63) && code_point_is(next_ch.clone(), 63)) { return emit( pos.clone(), TokenShape::ShNullCoalesce, @@ -689,7 +723,7 @@ pub fn scan_token( source.file.clone(), ); } - if ((ch.clone() == 46) && (next_ch.clone() == 46)) { + if ((ch.clone() == 46) && code_point_is(next_ch.clone(), 46)) { return emit( pos.clone(), TokenShape::ShDotDot, @@ -799,7 +833,7 @@ pub fn scan_token( }); } } - let ch_text = source_char(source.clone(), pos.pos.clone()); + let ch_text = v1_rt::from_code_point(ch.clone()); match v1_rt::lookup(&single_punct(), ch_text.clone()) { Some(sh) => emit( pos.clone(), @@ -877,12 +911,11 @@ pub fn scan_ident( pub fn scan_number(source: Rc, pos: Rc) -> Rc { { let int_end = source_scan_while(source.clone(), pos.pos.clone(), is_digit); - if (((v1_rt::int_add(int_end.clone(), 1) < source_len(source.clone())) - && (source_code_point(source.clone(), int_end.clone()) == 46)) - && is_digit(source_code_point( - source.clone(), - v1_rt::int_add(int_end.clone(), 1), - ))) + if (code_point_is(source_code_point(source.clone(), int_end.clone()), 46) + && code_point_satisfies( + source_code_point(source.clone(), v1_rt::int_add(int_end.clone(), 1)), + is_digit, + )) { { let frac_end = @@ -1121,91 +1154,100 @@ pub fn scan_string_body( let mut pos = __tco_loop_pos; #[allow(unused_mut)] let mut acc = __tco_loop_acc; - if (pos.clone() >= source_len(source.clone())) { - break Rc::new(StringScanResult::UnterminatedString { - content: acc.clone(), - end_pos: pos.clone(), - }); - } else { - let ch = source.source_chars.clone()[(pos.clone()) as usize].clone(); - if (ch.clone() == 34) { - break Rc::new(StringScanResult::ClosedString { + match (source.source_chars.clone()) + .get((pos.clone()) as usize) + .cloned() + { + std::option::Option::None => { + break Rc::new(StringScanResult::UnterminatedString { content: acc.clone(), end_pos: pos.clone(), }); - } else { - if (ch.clone() == 92) { - if (v1_rt::int_add(pos.clone(), 1) < source_len(source.clone())) { - let escaped = source.source_chars.clone() - [(v1_rt::int_add(pos.clone(), 1)) as usize] - .clone(); - if (((escaped.clone() == 117) - && (v1_rt::int_add(pos.clone(), 2) < source_len(source.clone()))) - && (source.source_chars.clone() - [(v1_rt::int_add(pos.clone(), 2)) as usize] - .clone() - == 123)) + } + Some(ch) => { + if (ch.clone() == 34) { + break Rc::new(StringScanResult::ClosedString { + content: acc.clone(), + end_pos: pos.clone(), + }); + } else { + if (ch.clone() == 92) { + match (source.source_chars.clone()) + .get((v1_rt::int_add(pos.clone(), 1)) as usize) + .cloned() { - { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(pos, 3); - let __tco_2 = v1_rt::rc_list_push( - v1_rt::rc_list_push(v1_rt::rc_list_push(acc, 92), 117), - 123, - ); - __tco_loop_source = __tco_0; - __tco_loop_pos = __tco_1; - __tco_loop_acc = __tco_2; - continue; + Some(escaped) => { + if ((escaped.clone() == 117) + && code_point_is( + (source.source_chars.clone()) + .get((v1_rt::int_add(pos.clone(), 2)) as usize) + .cloned(), + 123, + )) + { + { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(pos, 3); + let __tco_2 = v1_rt::rc_list_push( + v1_rt::rc_list_push(v1_rt::rc_list_push(acc, 92), 117), + 123, + ); + __tco_loop_source = __tco_0; + __tco_loop_pos = __tco_1; + __tco_loop_acc = __tco_2; + continue; + } + } else { + { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(pos, 2); + let __tco_2 = v1_rt::rc_list_push( + v1_rt::rc_list_push(acc, 92), + escaped.clone(), + ); + __tco_loop_source = __tco_0; + __tco_loop_pos = __tco_1; + __tco_loop_acc = __tco_2; + continue; + } + } } - } else { - { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(pos, 2); - let __tco_2 = v1_rt::rc_list_push( - v1_rt::rc_list_push(acc, 92), - escaped.clone(), - ); - __tco_loop_source = __tco_0; - __tco_loop_pos = __tco_1; - __tco_loop_acc = __tco_2; - continue; + std::option::Option::None => { + break Rc::new(StringScanResult::UnterminatedString { + content: v1_rt::rc_list_push(acc.clone(), 92), + end_pos: v1_rt::int_add(pos.clone(), 1), + }); } } } else { - break Rc::new(StringScanResult::UnterminatedString { - content: v1_rt::rc_list_push(acc.clone(), 92), - end_pos: v1_rt::int_add(pos.clone(), 1), - }); - } - } else { - if (ch.clone() == 123) { - if should_start_interpolation(source.clone(), pos.clone()) { - break Rc::new(StringScanResult::InterpolationStart { - content: acc.clone(), - end_pos: pos.clone(), - }); + if (ch.clone() == 123) { + if should_start_interpolation(source.clone(), pos.clone()) { + break Rc::new(StringScanResult::InterpolationStart { + content: acc.clone(), + end_pos: pos.clone(), + }); + } else { + { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(pos, 1); + let __tco_2 = v1_rt::rc_list_push(acc, 123); + __tco_loop_source = __tco_0; + __tco_loop_pos = __tco_1; + __tco_loop_acc = __tco_2; + continue; + } + } } else { { let __tco_0 = source; let __tco_1 = v1_rt::int_add(pos, 1); - let __tco_2 = v1_rt::rc_list_push(acc, 123); + let __tco_2 = v1_rt::rc_list_push(acc, ch.clone()); __tco_loop_source = __tco_0; __tco_loop_pos = __tco_1; __tco_loop_acc = __tco_2; continue; } } - } else { - { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(pos, 1); - let __tco_2 = v1_rt::rc_list_push(acc, ch.clone()); - __tco_loop_source = __tco_0; - __tco_loop_pos = __tco_1; - __tco_loop_acc = __tco_2; - continue; - } } } } @@ -1214,14 +1256,12 @@ pub fn scan_string_body( } pub fn should_start_interpolation(source: Rc, pos: i64) -> bool { - if (v1_rt::int_add(pos.clone(), 1) >= source_len(source.clone())) { - false - } else { - { - let next = source_code_point(source.clone(), v1_rt::int_add(pos.clone(), 1)); + match source_code_point(source.clone(), v1_rt::int_add(pos.clone(), 1)) { + Some(next) => { (((is_ident_start(next.clone()) || (next.clone() == 40)) || (next.clone() == 33)) || (next.clone() == 45)) } + std::option::Option::None => false, } } @@ -1229,10 +1269,6 @@ pub fn process_escapes(chars: Rc>) -> Rc { process_escapes_loop(chars.clone(), 0, Rc::new(vec![])) } -pub fn code_point_at(chars: Rc>, pos: i64) -> i64 { - chars.clone()[(pos.clone()) as usize].clone() -} - pub fn escape_receipt_seed_growth_mark() -> String { thread_local! { static CACHED: String = { @@ -1298,39 +1334,42 @@ pub fn unicode_escape_at( let mut digit_count = __tco_loop_digit_count; #[allow(unused_mut)] let mut value = __tco_loop_value; - if (pos.clone() >= (source.clone().len() as i64)) { - break std::option::Option::None; - } else { - let ch = code_point_at(source.clone(), pos.clone()); - if (ch.clone() == 125) { - if ((digit_count.clone() > 0) - && crate::std_unicode_types::unicode_scalar(value.clone())) - { - break Some(UnicodeEscape { - code_point: value.clone(), - next_pos: v1_rt::int_add(pos.clone(), 1), - }); - } else { - break std::option::Option::None; - } - } else { - if (digit_count.clone() >= 6) { - break std::option::Option::None; + match (source.clone()).get((pos.clone()) as usize).cloned() { + std::option::Option::None => { + break std::option::Option::None; + } + Some(ch) => { + if (ch.clone() == 125) { + if ((digit_count.clone() > 0) + && crate::std_unicode_types::unicode_scalar(value.clone())) + { + break Some(UnicodeEscape { + code_point: value.clone(), + next_pos: v1_rt::int_add(pos.clone(), 1), + }); + } else { + break std::option::Option::None; + } } else { - match hex_digit_value(ch.clone()) { - Some(digit) => { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(pos, 1); - let __tco_2 = v1_rt::int_add(digit_count, 1); - let __tco_3 = v1_rt::int_add(v1_rt::int_mul(value, 16), digit.clone()); - __tco_loop_source = __tco_0; - __tco_loop_pos = __tco_1; - __tco_loop_digit_count = __tco_2; - __tco_loop_value = __tco_3; - continue; - } - std::option::Option::None => { - break std::option::Option::None; + if (digit_count.clone() >= 6) { + break std::option::Option::None; + } else { + match hex_digit_value(ch.clone()) { + Some(digit) => { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(pos, 1); + let __tco_2 = v1_rt::int_add(digit_count, 1); + let __tco_3 = + v1_rt::int_add(v1_rt::int_mul(value, 16), digit.clone()); + __tco_loop_source = __tco_0; + __tco_loop_pos = __tco_1; + __tco_loop_digit_count = __tco_2; + __tco_loop_value = __tco_3; + continue; + } + std::option::Option::None => { + break std::option::Option::None; + } } } } @@ -1351,48 +1390,33 @@ pub fn process_escapes_loop( let mut pos = __tco_loop_pos; #[allow(unused_mut)] let mut acc = __tco_loop_acc; - if (pos.clone() >= (source.clone().len() as i64)) { - break Rc::new(EscapeProcessResult::EscapesProcessed { - text: v1_rt::chars_to_string(&acc, 0, (acc.clone().len() as i64)), - }); - } else { - let ch = code_point_at(source.clone(), pos.clone()); - if (ch.clone() == 92) { - if (v1_rt::int_add(pos.clone(), 1) >= (source.clone().len() as i64)) { - break Rc::new(EscapeProcessResult::EscapeProcessingRefused {}); + match (source.clone()).get((pos.clone()) as usize).cloned() { + std::option::Option::None => { + break Rc::new(EscapeProcessResult::EscapesProcessed { + text: v1_rt::chars_to_string(&acc, 0, (acc.clone().len() as i64)), + }); + } + Some(ch) => { + if (ch.clone() != 92) { + { + let __tco_0 = source; + let __tco_1 = v1_rt::int_add(pos, 1); + let __tco_2 = v1_rt::rc_list_push(acc, ch.clone()); + __tco_loop_source = __tco_0; + __tco_loop_pos = __tco_1; + __tco_loop_acc = __tco_2; + continue; + } } else { - let next = code_point_at(source.clone(), v1_rt::int_add(pos.clone(), 1)); - if ((next.clone() == 120) - && (v1_rt::int_add(pos.clone(), 3) < (source.clone().len() as i64))) + match (source.clone()) + .get((v1_rt::int_add(pos.clone(), 1)) as usize) + .cloned() { - let hi = code_point_at(source.clone(), v1_rt::int_add(pos.clone(), 2)); - let lo = code_point_at(source.clone(), v1_rt::int_add(pos.clone(), 3)); - match hex_escape_char(hi.clone(), lo.clone()) { - Some(decoded) => { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(pos, 4); - let __tco_2 = v1_rt::rc_list_push(acc, decoded.clone()); - __tco_loop_source = __tco_0; - __tco_loop_pos = __tco_1; - __tco_loop_acc = __tco_2; - continue; - } - std::option::Option::None => { - break Rc::new(EscapeProcessResult::EscapeProcessingRefused {}); - } + std::option::Option::None => { + break Rc::new(EscapeProcessResult::EscapeProcessingRefused {}); } - } else { - if (((next.clone() == 117) - && (v1_rt::int_add(pos.clone(), 2) < (source.clone().len() as i64))) - && (code_point_at(source.clone(), v1_rt::int_add(pos.clone(), 2)) - == 123)) - { - match unicode_escape_at( - source.clone(), - v1_rt::int_add(pos.clone(), 3), - 0, - 0, - ) { + Some(next) => { + match escape_decoding(source.clone(), pos.clone(), next.clone()) { Some(decoded) => { let __tco_0 = source; let __tco_1 = decoded.next_pos.clone(); @@ -1407,66 +1431,86 @@ pub fn process_escapes_loop( break Rc::new(EscapeProcessResult::EscapeProcessingRefused {}); } } + } + } + } + } + } + } +} + +pub fn escape_decoding(source: Rc>, pos: i64, next: i64) -> Option { + if (next.clone() == 120) { + match (source.clone()) + .get((v1_rt::int_add(pos.clone(), 2)) as usize) + .cloned() + { + Some(hi) => match (source.clone()) + .get((v1_rt::int_add(pos.clone(), 3)) as usize) + .cloned() + { + Some(lo) => match hex_escape_char(hi.clone(), lo.clone()) { + Some(decoded) => Some(UnicodeEscape { + code_point: decoded.clone(), + next_pos: v1_rt::int_add(pos.clone(), 4), + }), + std::option::Option::None => std::option::Option::None, + }, + std::option::Option::None => std::option::Option::None, + }, + std::option::Option::None => std::option::Option::None, + } + } else { + if ((next.clone() == 117) + && code_point_is( + (source.clone()) + .get((v1_rt::int_add(pos.clone(), 2)) as usize) + .cloned(), + 123, + )) + { + unicode_escape_at(source.clone(), v1_rt::int_add(pos.clone(), 3), 0, 0) + } else { + { + let simple = if (next.clone() == 34) { + Some(34) + } else { + if (next.clone() == 48) { + Some(0) + } else { + if (next.clone() == 92) { + Some(92) } else { - let decoded = if (next.clone() == 34) { - Some(34) + if (next.clone() == 110) { + Some(10) } else { - if (next.clone() == 48) { - Some(0) + if (next.clone() == 114) { + Some(13) } else { - if (next.clone() == 92) { - Some(92) + if (next.clone() == 116) { + Some(9) } else { - if (next.clone() == 110) { - Some(10) + if (next.clone() == 123) { + Some(123) } else { - if (next.clone() == 114) { - Some(13) + if (next.clone() == 125) { + Some(125) } else { - if (next.clone() == 116) { - Some(9) - } else { - if (next.clone() == 123) { - Some(123) - } else { - if (next.clone() == 125) { - Some(125) - } else { - std::option::Option::None - } - } - } + std::option::Option::None } } } } - }; - match decoded.clone() { - Some(code_point) => { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(pos, 2); - let __tco_2 = v1_rt::rc_list_push(acc, code_point.clone()); - __tco_loop_source = __tco_0; - __tco_loop_pos = __tco_1; - __tco_loop_acc = __tco_2; - continue; - } - std::option::Option::None => { - break Rc::new(EscapeProcessResult::EscapeProcessingRefused {}); - } } } } - } - } else { - { - let __tco_0 = source; - let __tco_1 = v1_rt::int_add(pos, 1); - let __tco_2 = v1_rt::rc_list_push(acc, ch.clone()); - __tco_loop_source = __tco_0; - __tco_loop_pos = __tco_1; - __tco_loop_acc = __tco_2; - continue; + }; + match simple.clone() { + Some(code_point) => Some(UnicodeEscape { + code_point: code_point.clone(), + next_pos: v1_rt::int_add(pos.clone(), 2), + }), + std::option::Option::None => std::option::Option::None, } } } From f12169a2a5c7e39c3cddb874eca5a9ec18ba48f1 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 03:24:26 +0000 Subject: [PATCH 14/69] floor_cost_distribution: percentile note at declaration grain Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/floor_cost_distribution.dag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dag/gunbc/floor_cost_distribution.dag b/dag/gunbc/floor_cost_distribution.dag index 7eec8739cf0..e429312916d 100644 --- a/dag/gunbc/floor_cost_distribution.dag +++ b/dag/gunbc/floor_cost_distribution.dag @@ -1081,12 +1081,12 @@ fn identity_inflation_permille(base: RunCost, other: RunCost, min_base_ms: Milli } // An order statistic over the observed values: `percent` is 0-100 and the result is always a -// member of the input, so it is a measurement and not an interpolation. +// member of the input, so it is a measurement and not an interpolation. The index read is the +// answer: an empty input has no member at any rank, so it is absent. fn permille_percentile(values: List, percent: Int) -> Int? { let sorted = values |> sort_by(v => v) let n = count(sorted) let idx = (percent * n) / 100 - // The index read is the answer: an empty input has no member at any rank, so it is absent. if idx >= n { sorted[n - 1] } else { sorted[idx] } } From 788be84ebb46918989f96682ed8e4f98442cf027 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 03:25:32 +0000 Subject: [PATCH 15/69] G (body): an Optional in a data row is spelled as the target's native option in JSON Present { value: v } serializes as v and Absent as null, instead of a lookup in the coproduct wire index that spelled Present as an internally tagged map (runtime serde refusal) or refused when Optional is outside the closure (fleet_tailnet_domain). Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/05_emit.dag | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index ef33d84d217..a2d7f96866c 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -492,6 +492,26 @@ fn emit_data_fields_json(value: Node, source_indices: Map, ) } +// AN OPTIONAL IN A DATA ROW IS SPELLED AS THE TARGET'S NATIVE OPTION, NOT AS A DECLARED COPRODUCT. +// Every target realizes Optional natively (Rust Option, Python None, Go nil), and each one's JSON +// reading of that option is transparent: Absent is `null`, `Present { value: v }` is `v` itself. +// Looking Optional up in the wire-spelling index spelled Present as an internally tagged +// `{"_variant": "Present", "value": ..}`, which the native option cannot parse (serde: "invalid +// type: map, expected a string" at run time), and where Optional is not declared inside the +// closure -- gunbc.fleet_tailnet fleet_tailnet_domain -- the lookup refused outright. Control: +// gunbc.instruments.native_emission_controls optional_data_row_cases. +fn emit_optional_data_value_json(value: Node, source_indices: Map, variant_wire: Map) -> EmitterOutcome { + match value.children |> first { + Absent => Emitted { json: "null" } + Present { value: payload_field } => + if (value.children |> count) == 1 { + emit_data_value_json(value: field_init_node_value(n: payload_field), source_indices: source_indices, variant_wire: variant_wire) + } else { + Refused { reason: "an Optional variant literal carries more than its one payload field" } + } + } +} + fn emit_data_value_json(value: Node, source_indices: Map, variant_wire: Map) -> EmitterOutcome { match value.expr_data { ExprLiteral { value: v } => match v { @@ -514,6 +534,9 @@ fn emit_data_value_json(value: Node, source_indices: Map, ExprRecordLit { parent_enum: pe } => match pe { Present { value: parent } => + if qualified_last_segment(name: parent) == "Optional" { + emit_optional_data_value_json(value: value, source_indices: source_indices, variant_wire: variant_wire) + } else { match record_lit_type_name_at(texpr: value, source_indices: source_indices) { Absent => Refused { reason: concat("variant record literal with parent coproduct ", parent, " carries no authored head name to key the wire-spelling index") } Present { value: head } => @@ -546,6 +569,7 @@ fn emit_data_value_json(value: Node, source_indices: Map, } } } + } Absent => if (value.children |> count) == 0 { Emitted { json: "null" } From a2d87decdd37197f47d23f1d9e8c358e8a08d0b0 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 03:47:22 +0000 Subject: [PATCH 16/69] floor roster: retire proc_mountinfo#length as ImportsFixed (the index rewrite dropped the bare length call) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag b/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag index 01d20a5690f..e1150bd1696 100644 --- a/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag +++ b/src/v2/workflow/floor_unimported_bare_provider_debt_roster.dag @@ -246,7 +246,7 @@ data unimported_bare_provider_dispositions: List Date: Sun, 4 Oct 2026 03:56:55 +0000 Subject: [PATCH 17/69] G: regenerated v1_compiler_emit.rs Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit.rs | 141 +++++++++++++++----------- 1 file changed, 84 insertions(+), 57 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 9ce23cc26ee..0a7eecce4c7 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -1023,6 +1023,32 @@ pub fn emit_data_fields_json( ) } +pub fn emit_optional_data_value_json( + value: Rc, + source_indices: Rc>>, + variant_wire: Rc>>, +) -> Rc { + match value.children.clone().first().cloned() { + std::option::Option::None => Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }), + Some(payload_field) => { + if ((value.children.clone().len() as i64) == 1) { + emit_data_value_json( + crate::v1_std_core::field_init_node_value(payload_field.clone()), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + Rc::new(EmitterOutcome::Refused { + reason: "an Optional variant literal carries more than its one payload field" + .to_string(), + }) + } + } + } +} + pub fn emit_data_value_json( value: Rc, source_indices: Rc>>, @@ -1098,27 +1124,25 @@ pub fn emit_data_value_json( } ExprData::ExprRecordLit { parent_enum: pe, .. - } => match pe.clone() { - Some(parent) => match crate::v1_std_core::record_lit_type_name_at( - value.clone(), - source_indices.clone(), - ) { - std::option::Option::None => Rc::new(EmitterOutcome::Refused { - reason: v1_rt::concat( - v1_rt::concat( - "variant record literal with parent coproduct ".to_string(), - parent.clone(), - ), - " carries no authored head name to key the wire-spelling index" - .to_string(), - ), - }), - Some(head) => { - let key = v1_rt::concat( - v1_rt::concat(parent.clone(), ".".to_string()), - crate::v1_std_core::qualified_last_segment(head.clone()), - ); - match v1_rt::map_get(&variant_wire, key.clone()) { + } => { + match pe.clone() { + Some(parent) => { + if (crate::v1_std_core::qualified_last_segment(parent.clone()) + == "Optional".to_string()) + { + emit_optional_data_value_json( + value.clone(), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + match crate::v1_std_core::record_lit_type_name_at(value.clone(), source_indices.clone()) { + std::option::Option::None => Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat("variant record literal with parent coproduct ".to_string(), parent.clone()), " carries no authored head name to key the wire-spelling index".to_string()), +}), + Some(head) => { + let key = v1_rt::concat(v1_rt::concat(parent.clone(), ".".to_string()), crate::v1_std_core::qualified_last_segment(head.clone())); +match v1_rt::map_get(&variant_wire, key.clone()) { std::option::Option::None => Rc::new(EmitterOutcome::Refused { reason: v1_rt::concat(v1_rt::concat("no wire spelling indexed for ".to_string(), key.clone()), ": the index covers every coproduct declared in the emission closure it was built from, so this parent is outside that closure".to_string()), }), @@ -1127,11 +1151,11 @@ pub fn emit_data_value_json( reason: r.clone(), }), DataVariantWireSpelling::DataVariantUntagged => if ((value.children.clone().len() as i64) == 0) { - Rc::new(EmitterOutcome::Emitted { + Rc::new(EmitterOutcome::Emitted { json: "null".to_string(), }) - } else { - match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wire.clone())).clone() { + } else { + match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wire.clone())).clone() { JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => Rc::new(EmitterOutcome::Refused { reason: r.clone(), }), @@ -1139,18 +1163,18 @@ pub fn emit_data_value_json( json: v1_rt::concat(v1_rt::concat("{".to_string(), ps.clone().join(&", ".to_string())), "}".to_string()), }), } - }, + }, DataVariantWireSpelling::DataVariantBareString { tag: t, .. } => if ((value.children.clone().len() as i64) == 0) { - Rc::new(EmitterOutcome::Emitted { + Rc::new(EmitterOutcome::Emitted { json: v1_rt::concat(v1_rt::concat("\"".to_string(), crate::v1_compiler_emit_core_support::escape_json_string(t.clone())), "\"".to_string()), }) - } else { - Rc::new(EmitterOutcome::Refused { + } else { + Rc::new(EmitterOutcome::Refused { reason: v1_rt::concat(v1_rt::concat("variant ".to_string(), key.clone()), " carries fields under a StringVariant wire policy, which is nullary-only; the type-side emission of the parent coproduct refuses it too".to_string()), }) - }, + }, DataVariantWireSpelling::DataVariantInternalTagged { tag_field: tf, tag: t, .. } => { - let tag_piece = v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("\"".to_string(), crate::v1_compiler_emit_core_support::escape_json_string(tf.clone())), "\": \"".to_string()), crate::v1_compiler_emit_core_support::escape_json_string(t.clone())), "\"".to_string()); + let tag_piece = v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("\"".to_string(), crate::v1_compiler_emit_core_support::escape_json_string(tf.clone())), "\": \"".to_string()), crate::v1_compiler_emit_core_support::escape_json_string(t.clone())), "\"".to_string()); match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wire.clone())).clone() { JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => Rc::new(EmitterOutcome::Refused { reason: r.clone(), @@ -1162,39 +1186,42 @@ match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wir }, }, } +}, +} + } } - }, - std::option::Option::None => { - if ((value.children.clone().len() as i64) == 0) { - Rc::new(EmitterOutcome::Emitted { - json: "null".to_string(), - }) - } else { - match (*emit_data_fields_json( - value.clone(), - source_indices.clone(), - variant_wire.clone(), - )) - .clone() - { - JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => { - Rc::new(EmitterOutcome::Refused { reason: r.clone() }) - } - JsonFragmentsAccum::FragmentsAccumulated { pieces: ps, .. } => { - Rc::new(EmitterOutcome::Emitted { - json: v1_rt::concat( - v1_rt::concat( - "{".to_string(), - ps.clone().join(&", ".to_string()), + std::option::Option::None => { + if ((value.children.clone().len() as i64) == 0) { + Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }) + } else { + match (*emit_data_fields_json( + value.clone(), + source_indices.clone(), + variant_wire.clone(), + )) + .clone() + { + JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => { + Rc::new(EmitterOutcome::Refused { reason: r.clone() }) + } + JsonFragmentsAccum::FragmentsAccumulated { pieces: ps, .. } => { + Rc::new(EmitterOutcome::Emitted { + json: v1_rt::concat( + v1_rt::concat( + "{".to_string(), + ps.clone().join(&", ".to_string()), + ), + "}".to_string(), ), - "}".to_string(), - ), - }) + }) + } } } } } - }, + } ExprData::ExprVar { binding_kind: _, .. } => Rc::new(EmitterOutcome::Emitted { From c231bd11c90b87ffa388f3fc80d8a9ab7058da90 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 04:26:08 +0000 Subject: [PATCH 18/69] floor_cost_distribution: bind the row's module as row_module (module is a keyword) Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/floor_cost_distribution.dag | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dag/gunbc/floor_cost_distribution.dag b/dag/gunbc/floor_cost_distribution.dag index e429312916d..d54237163c1 100644 --- a/dag/gunbc/floor_cost_distribution.dag +++ b/dag/gunbc/floor_cost_distribution.dag @@ -555,7 +555,7 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo Absent => none Present { value: identity } => match fields[columns.module] { Absent => none - Present { value: module } => match parse_claim_cost_reading(fields: fields, columns: columns) { + Present { value: row_module } => match parse_claim_cost_reading(fields: fields, columns: columns) { Absent => none Present { value: reading } => match (match fields.skip(n: columns.verdict_reached).first() { Absent => none Present { value: cell } => parse_verdict_reached(value: cell) }) { Absent => none @@ -564,7 +564,7 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo ReachabilityColumnUnrecorded => Present { value: FloorCostRow { identity: identity, - module: module, + module: row_module, verdict_reached: reached, cost: reading, reachability: none @@ -573,7 +573,7 @@ fn parse_claim_cost_line(line: String, columns: ClaimCostColumns) -> FloorCostRo ReachabilityColumnRead { value: reach } => Present { value: FloorCostRow { identity: identity, - module: module, + module: row_module, verdict_reached: reached, cost: reading, reachability: Present { value: reach } From a0b56f466275236ee2d64aec6361bd7961a8cf56 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 05:22:08 +0000 Subject: [PATCH 19/69] infer mirror: start from main's generation (regenerated next) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 121 ++++++++++++++++--------- 1 file changed, 76 insertions(+), 45 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index bf1205a2c7f..b587c06fd71 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -74,9 +74,7 @@ use crate::std_literal_elaboration::LiteralElaborationOutcome::{ DirectLiteral, LiteralElaborationRefused, ViaHomomorphism, }; use crate::std_literal_elaboration::LiteralSourceKind::KernelIntLiteral; -use crate::std_literal_elaboration::LiteralUnfolding::{ - BooleanUnfold, PeanoUnfold, UnicodeScalarSequenceUnfold, -}; +use crate::std_literal_elaboration::LiteralUnfolding::{PeanoUnfold, UnicodeScalarSequenceUnfold}; pub use crate::std_literal_elaboration::{ elaborate_literal_at, kernel_grounding_for, literal_elaboration_refusal_message, literal_source_kind_of, @@ -188,7 +186,8 @@ pub use crate::v1_compiler_infer_lookup::{ }; pub use crate::v1_compiler_infer_method::{ builtin_host_text_param_names, builtin_kernel_seed_diagnostics, builtin_param_names, - infer_builtin_call_type, resolve_builtin_call_type, + infer_builtin_call_type, is_empty_map_constructor, is_empty_set_constructor, + resolve_builtin_call_type, }; use crate::v1_compiler_infer_patterns::PatternSubject::*; pub use crate::v1_compiler_infer_patterns::{ @@ -1924,6 +1923,7 @@ pub fn explicit_return_conformance_diags( "".to_string(), declared.clone(), expression_value_type(returned.clone()), + returned.clone(), returned.span.clone(), scope.clone(), )) @@ -2146,6 +2146,7 @@ pub fn declared_type_conformance_diags( subject: String, declared: Rc, produced: Rc, + produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2168,6 +2169,7 @@ pub fn declared_type_conformance_diags( subject.clone(), declared.clone(), produced.clone(), + produced_by.clone(), span.clone(), scope.clone(), ), @@ -2179,6 +2181,7 @@ pub fn declared_type_conformance_diags_core( subject: String, declared: Rc, produced: Rc, + produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2186,7 +2189,7 @@ pub fn declared_type_conformance_diags_core( let si = scope.type_env.clone().source_indices.clone(); let both_ground = (conformance_ground_type(declared.clone(), si.clone()) && conformance_ground_type(produced.clone(), si.clone())); - let cardinality_diags = optional_at_required_obligation_diags( + let cardinality_diags = optional_at_required_value_obligation_diags( Rc::new(DeclaredTypeObligation { position: position.clone(), subject: subject.clone(), @@ -2194,6 +2197,7 @@ pub fn declared_type_conformance_diags_core( produced: produced.clone(), span: span.clone(), }), + produced_by.clone(), scope.clone(), ); if ((cardinality_diags.clone().len() as i64) > 0) { @@ -6153,6 +6157,53 @@ pub fn optional_produced_at_required_declared( } } +pub fn expr_value_is_index_access(mut __tco_loop_e: Rc) -> bool { + loop { + #[allow(unused_mut)] + let mut e = __tco_loop_e; + match (*e.expr_data.clone()).clone() { + ExprData::ExprIndex => { + break true; + } + ExprData::ExprLet => match crate::v1_std_core::let_body(e.clone()) { + Some(body) => { + let __tco_0 = body.clone(); + __tco_loop_e = __tco_0; + continue; + } + std::option::Option::None => { + break false; + } + }, + ExprData::ExprBlock => match e.children.clone().last().cloned() { + Some(tail) => { + let __tco_0 = tail.clone(); + __tco_loop_e = __tco_0; + continue; + } + std::option::Option::None => { + break false; + } + }, + _ => { + break false; + } + } + } +} + +pub fn optional_at_required_value_obligation_diags( + obligation: Rc, + produced_by: Rc, + scope: Rc, +) -> Rc>> { + if expr_value_is_index_access(produced_by.clone()) { + Rc::new(vec![]) + } else { + optional_at_required_obligation_diags(obligation.clone(), scope.clone()) + } +} + pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, @@ -12132,23 +12183,6 @@ pub fn unfold_literal_image( }), }), 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() { - LiteralValue::LitBool { value: b, .. } => elaborated_expr_node(if b.clone() { - t.decl_name.clone() - } else { - f.decl_name.clone() - }, 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()), }, } } @@ -13424,13 +13458,10 @@ crate::v1_compiler_infer_types::resolve_type_variables_from_template(t.clone(), }) } } else { - if (!callee_is_body_binding.clone() - && (func_name.clone() == "empty_map".to_string())) - { - { - let bare_m = - crate::v1_compiler_infer_types::bare_map_node(); - match expected.clone() { + if (!callee_is_body_binding.clone() && crate::v1_compiler_infer_method::is_empty_map_constructor(func_name.clone())) { + { + let bare_m = crate::v1_compiler_infer_types::bare_map_node(); +match expected.clone() { Some(exp) => if crate::v1_compiler_infer_types::node_is_keyed_collection(exp.clone(), scope.type_env.clone().source_indices.clone()) { Rc::new(InferResult { typed: crate::v1_std_core::make_named_expr_node(texpr.occurrence_identity.clone(), func_name.clone(), Rc::new(ExprData::ExprCall { @@ -13514,15 +13545,12 @@ match bare_m.clone() { }), }, } - } - } else { - if (!callee_is_body_binding.clone() - && (func_name.clone() == "empty_set".to_string())) - { - { - let bare_s = - crate::v1_compiler_infer_types::bare_set_node(); - match expected.clone() { +} + } else { + if (!callee_is_body_binding.clone() && crate::v1_compiler_infer_method::is_empty_set_constructor(func_name.clone())) { + { + let bare_s = crate::v1_compiler_infer_types::bare_set_node(); +match expected.clone() { Some(exp) => if crate::v1_compiler_infer_types::node_is_set_collection(exp.clone(), scope.type_env.clone().source_indices.clone()) { Rc::new(InferResult { typed: crate::v1_std_core::make_named_expr_node(texpr.occurrence_identity.clone(), func_name.clone(), Rc::new(ExprData::ExprCall { @@ -13591,9 +13619,9 @@ match bare_s.clone() { }), }, } - } - } else { - if (!callee_is_body_binding.clone() && (crate::v1_compiler_infer_method::infer_builtin_call_type(func_name.clone()) != std::option::Option::None)) { +} + } else { + if (!callee_is_body_binding.clone() && (crate::v1_compiler_infer_method::infer_builtin_call_type(func_name.clone()) != std::option::Option::None)) { { let tier2b = infer_tier2b_builtin_with_kernel_diags(func_name.clone(), typed_args.clone(), scope.clone(), span.clone()); let bt = tier2b.bt.clone(); @@ -13726,8 +13754,8 @@ Rc::new(InferResult { } } } - } - } + } + } } } } @@ -14568,6 +14596,7 @@ crate::v1_compiler_infer_types::resolve_type_variables_from_template(t.clone(), let_name.clone(), declared.clone(), produced_value_type.clone(), + val_typed.clone(), val_expr.span.clone(), scope.clone(), ); @@ -17254,13 +17283,13 @@ let field_type_diags = match field_declared_type.clone() { let field_cardinality_diags = if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) } else { - optional_at_required_obligation_diags(Rc::new(DeclaredTypeObligation { + optional_at_required_value_obligation_diags(Rc::new(DeclaredTypeObligation { position: DeclaredTypePosition::PositionRecordLiteralField, subject: fi_name.clone(), declared: expected_node.clone(), produced: got_node.clone(), span: ar_typed.span.clone(), -}), scope.clone()) +}), ar_typed.clone(), scope.clone()) }; if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) @@ -22941,6 +22970,7 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), declared_return_type_node(item.clone()), crate::v1_compiler_infer_types::resolved_type(body_typed.clone()), + body_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), @@ -23048,6 +23078,7 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), item.type_annotation.clone().clone().unwrap(), expression_value_type(val_typed.clone()), + val_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), From 4f3f7ad8f9d91e31dc85e3254f4bb84ca8f8874e Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 05:41:02 +0000 Subject: [PATCH 20/69] stage0: regenerate the infer mirror on the merged tree (fixed point at second generation) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 61 ++------------------------ 1 file changed, 3 insertions(+), 58 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index b587c06fd71..d0595364414 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -1923,7 +1923,6 @@ pub fn explicit_return_conformance_diags( "".to_string(), declared.clone(), expression_value_type(returned.clone()), - returned.clone(), returned.span.clone(), scope.clone(), )) @@ -2146,7 +2145,6 @@ pub fn declared_type_conformance_diags( subject: String, declared: Rc, produced: Rc, - produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2169,7 +2167,6 @@ pub fn declared_type_conformance_diags( subject.clone(), declared.clone(), produced.clone(), - produced_by.clone(), span.clone(), scope.clone(), ), @@ -2181,7 +2178,6 @@ pub fn declared_type_conformance_diags_core( subject: String, declared: Rc, produced: Rc, - produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2189,7 +2185,7 @@ pub fn declared_type_conformance_diags_core( let si = scope.type_env.clone().source_indices.clone(); let both_ground = (conformance_ground_type(declared.clone(), si.clone()) && conformance_ground_type(produced.clone(), si.clone())); - let cardinality_diags = optional_at_required_value_obligation_diags( + let cardinality_diags = optional_at_required_obligation_diags( Rc::new(DeclaredTypeObligation { position: position.clone(), subject: subject.clone(), @@ -2197,7 +2193,6 @@ pub fn declared_type_conformance_diags_core( produced: produced.clone(), span: span.clone(), }), - produced_by.clone(), scope.clone(), ); if ((cardinality_diags.clone().len() as i64) > 0) { @@ -6157,53 +6152,6 @@ pub fn optional_produced_at_required_declared( } } -pub fn expr_value_is_index_access(mut __tco_loop_e: Rc) -> bool { - loop { - #[allow(unused_mut)] - let mut e = __tco_loop_e; - match (*e.expr_data.clone()).clone() { - ExprData::ExprIndex => { - break true; - } - ExprData::ExprLet => match crate::v1_std_core::let_body(e.clone()) { - Some(body) => { - let __tco_0 = body.clone(); - __tco_loop_e = __tco_0; - continue; - } - std::option::Option::None => { - break false; - } - }, - ExprData::ExprBlock => match e.children.clone().last().cloned() { - Some(tail) => { - let __tco_0 = tail.clone(); - __tco_loop_e = __tco_0; - continue; - } - std::option::Option::None => { - break false; - } - }, - _ => { - break false; - } - } - } -} - -pub fn optional_at_required_value_obligation_diags( - obligation: Rc, - produced_by: Rc, - scope: Rc, -) -> Rc>> { - if expr_value_is_index_access(produced_by.clone()) { - Rc::new(vec![]) - } else { - optional_at_required_obligation_diags(obligation.clone(), scope.clone()) - } -} - pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, @@ -14596,7 +14544,6 @@ crate::v1_compiler_infer_types::resolve_type_variables_from_template(t.clone(), let_name.clone(), declared.clone(), produced_value_type.clone(), - val_typed.clone(), val_expr.span.clone(), scope.clone(), ); @@ -17283,13 +17230,13 @@ let field_type_diags = match field_declared_type.clone() { let field_cardinality_diags = if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) } else { - optional_at_required_value_obligation_diags(Rc::new(DeclaredTypeObligation { + optional_at_required_obligation_diags(Rc::new(DeclaredTypeObligation { position: DeclaredTypePosition::PositionRecordLiteralField, subject: fi_name.clone(), declared: expected_node.clone(), produced: got_node.clone(), span: ar_typed.span.clone(), -}), ar_typed.clone(), scope.clone()) +}), scope.clone()) }; if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) @@ -22970,7 +22917,6 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), declared_return_type_node(item.clone()), crate::v1_compiler_infer_types::resolved_type(body_typed.clone()), - body_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), @@ -23078,7 +23024,6 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), item.type_annotation.clone().clone().unwrap(), expression_value_type(val_typed.clone()), - val_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), From 59b5231a895ee98246bb14d0bfe02fd47899f5e9 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 06:31:23 +0000 Subject: [PATCH 21/69] G: regenerate v1_compiler_emit_rust.rs over merged main Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 0994f20b173..7e6431d4400 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -38783,18 +38783,21 @@ pub fn emit_data_def( annotation_type_node.clone(), scope.type_env.clone().source_indices.clone(), ) { - crate::v1_compiler_coercion::coerce_primitive_type( - crate::v1_compiler_coercion::type_reference_realization( - annotation_type_node.clone(), + rust_carrier_optional_wrap( + annotation_type_node.clone(), + crate::v1_compiler_coercion::coerce_primitive_type( + crate::v1_compiler_coercion::type_reference_realization( + annotation_type_node.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + annotation_type_node.clone(), + ), + RenderTarget::Rust, + ), crate::v1_std_core::authored_name_at( scope.type_env.clone().source_indices.clone(), annotation_type_node.clone(), ), - RenderTarget::Rust, - ), - crate::v1_std_core::authored_name_at( - scope.type_env.clone().source_indices.clone(), - annotation_type_node.clone(), ), ) } else { From b6d8c55e6b1044040596a690b0c57b4d62ee647b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 09:36:41 +0000 Subject: [PATCH 22/69] G (review): select the native-option serializer by the row's declared cardinality, not a leaf spelling Removes the qualified_last_segment(parent) == "Optional" branch from emit_data_value_json. emit_data_def_body now asks emit_declared_optional_row_json only for a row declared T?, so a coproduct merely named Optional keeps its wire policy. Adds that collision case to native-emission-controls. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../instruments/native_emission_controls.dag | 11 +++- ...e_emission_controls_optional_collision.dag | 21 ++++++++ src/v1/05_emit.dag | 52 ++++++++++++------- src/v1/05_emit_rust.dag | 9 +++- 4 files changed, 69 insertions(+), 24 deletions(-) create mode 100644 dag/gunbc/instruments/native_emission_controls_optional_collision.dag diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index 1ce1545d223..b63d5be463a 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -2,6 +2,7 @@ module gunbc.instruments.native_emission_controls import std.types { Bool, Int, List, NonEmptyStr, Set, String } import v2.std.algebra { filter } +import gunbc.instruments.native_emission_controls_optional_collision { collision_wrapped_row, collision_row_value } import extdeps.filesystem.filesystem_io { Filesystem } import std.compiler_entry { CompilerEntryDriver, NativeClaimDriver, NativeClaimReport, NativeClaimTerminal, NativeClaimHeld, NativeClaimNotHeld } @@ -135,7 +136,8 @@ fn filter_in_branch_condition_cases() -> List { // where-refinement such as NonEmptyStr took the one arm of emit_data_def with no optional wrap, so // gunbc.fleet_tailnet fleet_tailnet_domain (`NonEmptyStr? = Present { .. }`) was emitted // `-> NonEmptyStr`; and the JSON body spelled Present as a tagged map the native option cannot -// parse. Both rows pass through a `T?`-typed parameter, so a dropped `?` stops this closure +// parse. A third row, of a non-kernel coproduct NAMED Optional, must keep its own wire policy. +// Both optional rows pass through a `T?`-typed parameter, so a dropped `?` stops this closure // compiling, and a wrong body stops it at run time; the cases decide each row answers as declared. data control_optional_brand_present: NonEmptyStr? = Present { value: "tailnet.example" } @@ -157,6 +159,10 @@ fn optional_data_row_cases() -> List { NativeEmissionCase { identity: "optional_data_row_red_absent_answers_absent", held: control_optional_brand_value(d: control_optional_brand_absent) == "" + }, + NativeEmissionCase { + identity: "optional_named_coproduct_row_keeps_its_wire_policy", + held: collision_row_value(o: collision_wrapped_row) == 7 } ] } @@ -196,7 +202,8 @@ data native_emission_expected_identities: List = [ "filter_guard_receipt_red_empty_tag_short_circuits", "claim_driver_filesystem_absent_path_read_is_refused", "optional_data_row_present_answers_its_value", - "optional_data_row_red_absent_answers_absent" + "optional_data_row_red_absent_answers_absent", + "optional_named_coproduct_row_keeps_its_wire_policy" ] fn native_emission_cases() -> List { diff --git a/dag/gunbc/instruments/native_emission_controls_optional_collision.dag b/dag/gunbc/instruments/native_emission_controls_optional_collision.dag new file mode 100644 index 00000000000..f7aa3b7ad11 --- /dev/null +++ b/dag/gunbc/instruments/native_emission_controls_optional_collision.dag @@ -0,0 +1,21 @@ +module gunbc.instruments.native_emission_controls_optional_collision + +import std.types { Int } + +// A NON-KERNEL COPRODUCT THAT HAPPENS TO BE NAMED Optional, for the collision case in +// gunbc.instruments.native_emission_controls. Its data row has no `?`, so it must be serialized under +// its own wire policy like any other declared coproduct. A serializer that chose the native option by +// the parent's LEAF SPELLING would spell this row as its bare payload, which the emitted enum cannot +// parse (review on gunbc#13202). +type Optional + = CollisionWrapped { value: Int } + | CollisionEmpty + +data collision_wrapped_row: Optional = CollisionWrapped { value: 7 } + +fn collision_row_value(o: Optional) -> Int { + match o { + CollisionWrapped { value: v } => v + CollisionEmpty => 0 + } +} diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index a2d7f96866c..86cd8fef3a0 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -492,23 +492,39 @@ fn emit_data_fields_json(value: Node, source_indices: Map, ) } -// AN OPTIONAL IN A DATA ROW IS SPELLED AS THE TARGET'S NATIVE OPTION, NOT AS A DECLARED COPRODUCT. -// Every target realizes Optional natively (Rust Option, Python None, Go nil), and each one's JSON -// reading of that option is transparent: Absent is `null`, `Present { value: v }` is `v` itself. -// Looking Optional up in the wire-spelling index spelled Present as an internally tagged -// `{"_variant": "Present", "value": ..}`, which the native option cannot parse (serde: "invalid -// type: map, expected a string" at run time), and where Optional is not declared inside the -// closure -- gunbc.fleet_tailnet fleet_tailnet_domain -- the lookup refused outright. Control: -// gunbc.instruments.native_emission_controls optional_data_row_cases. -fn emit_optional_data_value_json(value: Node, source_indices: Map, variant_wire: Map) -> EmitterOutcome { - match value.children |> first { - Absent => Emitted { json: "null" } - Present { value: payload_field } => - if (value.children |> count) == 1 { - emit_data_value_json(value: field_init_node_value(n: payload_field), source_indices: source_indices, variant_wire: variant_wire) - } else { - Refused { reason: "an Optional variant literal carries more than its one payload field" } +// A DATA ROW DECLARED `T?` IS SPELLED AS THE TARGET'S NATIVE OPTION, selected by the row's DECLARED +// cardinality -- never by the spelling of a variant's parent. Every target realizes `T?` natively +// (Rust Option, Python None, Go nil), and each one's JSON reading of it is transparent: absent is +// `null`, present is the payload itself. The caller (v1.compiler.emit_rust emit_data_def_body) asks +// this only for a row whose declared type carries CardOptional, so an unrelated coproduct that happens +// to be NAMED Optional keeps its own wire policy (review on gunbc#13202: a leaf-name test here was a +// second, unrostered authority that would have serialized such a coproduct as null or a bare payload). +// Within an optional row, a variant literal whose parent IS the declared inner type is a value of T +// and is spelled as one; any other one-field variant literal is the option's present arm and is +// unwrapped to its payload. Control: gunbc.instruments.native_emission_controls optional_data_row_cases +// and its Optional-named collision case. +fn emit_declared_optional_row_json(value: Node, inner_type_name: String, source_indices: Map, variant_wire: Map) -> EmitterOutcome { + match value.expr_data { + ExprLiteral { value: LitNull } => Emitted { json: "null" } + ExprRecordLit { parent_enum: pe } => + match pe { + Present { value: parent } => + if qualified_last_segment(name: parent) == qualified_last_segment(name: inner_type_name) { + emit_data_value_json(value: value, source_indices: source_indices, variant_wire: variant_wire) + } else { + match value.children |> first { + Absent => Emitted { json: "null" } + Present { value: payload_field } => + if (value.children |> count) == 1 { + emit_data_value_json(value: field_init_node_value(n: payload_field), source_indices: source_indices, variant_wire: variant_wire) + } else { + Refused { reason: concat("an optional row's present literal carries ", to_string(value.children |> count), " fields; the option's present arm carries exactly its payload") } + } + } + } + Absent => emit_data_value_json(value: value, source_indices: source_indices, variant_wire: variant_wire) } + _ => emit_data_value_json(value: value, source_indices: source_indices, variant_wire: variant_wire) } } @@ -534,9 +550,6 @@ fn emit_data_value_json(value: Node, source_indices: Map, ExprRecordLit { parent_enum: pe } => match pe { Present { value: parent } => - if qualified_last_segment(name: parent) == "Optional" { - emit_optional_data_value_json(value: value, source_indices: source_indices, variant_wire: variant_wire) - } else { match record_lit_type_name_at(texpr: value, source_indices: source_indices) { Absent => Refused { reason: concat("variant record literal with parent coproduct ", parent, " carries no authored head name to key the wire-spelling index") } Present { value: head } => @@ -569,7 +582,6 @@ fn emit_data_value_json(value: Node, source_indices: Map, } } } - } Absent => if (value.children |> count) == 0 { Emitted { json: "null" } diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 8aa6c4e273a..c4d1cd2620e 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -252,7 +252,7 @@ import v1.compiler.emit { emit_lambda_params, emit_null_coalesce, emit_list_lit_expr, emit_shared_expr, emit_typed_cast_shared, emit_string_literal, emit_simple_expr, escape_rust_interp_text, module_emit_scope, scope_after_expr, lookup_item_by_identity, has_nested_records_node, - emit_data_value_json, EmitterOutcome, Emitted, Refused, is_null_coalesce, has_service_items, + emit_data_value_json, emit_declared_optional_row_json, EmitterOutcome, Emitted, Refused, is_null_coalesce, has_service_items, order_typed_call_args_from_semantics, is_tco_eligible, is_self_recursive, emit_shared_tco_expr, tco_reassign_core, shared_tco_reassign, tco_loop_slot_name, tco_loop_iteration_lets, service_fallback_transport, effective_operation_transport, ServiceFieldSet, compute_service_fields, service_field_decls, @@ -16922,7 +16922,12 @@ fn emit_data_def_body(type_node: Node, value: Node, registry: Map true _ => false } { concat(" ", emit_typed_expr(texpr: value, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024)) } else if has_nested_records_node(n: type_node, source_indices: scope.type_env.source_indices) && !data_value_has_cross_refs(value: value) && !data_row_type_forbids_deserialize(type_node: type_node, emit_info: emit_info, source_indices: scope.type_env.source_indices) { - match emit_data_value_json(value: value, source_indices: scope.type_env.source_indices, variant_wire: emit_info.data_variant_wire_spellings) { + let row_json = if type_node.return_cardinality == CardOptional { + emit_declared_optional_row_json(value: value, inner_type_name: authored_name_at(source_indices: scope.type_env.source_indices, node: type_node), source_indices: scope.type_env.source_indices, variant_wire: emit_info.data_variant_wire_spellings) + } else { + emit_data_value_json(value: value, source_indices: scope.type_env.source_indices, variant_wire: emit_info.data_variant_wire_spellings) + } + match row_json { Refused { reason: r } => concat(" compile_error!(\"", escape_string_literal_body(s: r), "\")") Emitted { json: json_str } => concat(" serde_json::from_str(\"", escape_string_literal_body(s: json_str), "\")\n", " .expect(\"valid data definition\")") From 9c036e2904ef2a9e32332531f552508e3f2288f8 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 09:56:04 +0000 Subject: [PATCH 23/69] G (review): named predicate for the declared-optional test; collision case withdrawn pending ruling A coproduct named Optional cannot be emitted at all today: type rendering treats any Optional leaf as the host option (is_host_optional_carrier_type and siblings), independent of the serializer. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../instruments/native_emission_controls.dag | 10 ++------- ...e_emission_controls_optional_collision.dag | 21 ------------------- src/v1/05_emit_rust.dag | 7 ++++++- 3 files changed, 8 insertions(+), 30 deletions(-) delete mode 100644 dag/gunbc/instruments/native_emission_controls_optional_collision.dag diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index b63d5be463a..b314c64e637 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -2,7 +2,6 @@ module gunbc.instruments.native_emission_controls import std.types { Bool, Int, List, NonEmptyStr, Set, String } import v2.std.algebra { filter } -import gunbc.instruments.native_emission_controls_optional_collision { collision_wrapped_row, collision_row_value } import extdeps.filesystem.filesystem_io { Filesystem } import std.compiler_entry { CompilerEntryDriver, NativeClaimDriver, NativeClaimReport, NativeClaimTerminal, NativeClaimHeld, NativeClaimNotHeld } @@ -136,7 +135,7 @@ fn filter_in_branch_condition_cases() -> List { // where-refinement such as NonEmptyStr took the one arm of emit_data_def with no optional wrap, so // gunbc.fleet_tailnet fleet_tailnet_domain (`NonEmptyStr? = Present { .. }`) was emitted // `-> NonEmptyStr`; and the JSON body spelled Present as a tagged map the native option cannot -// parse. A third row, of a non-kernel coproduct NAMED Optional, must keep its own wire policy. +// parse. // Both optional rows pass through a `T?`-typed parameter, so a dropped `?` stops this closure // compiling, and a wrong body stops it at run time; the cases decide each row answers as declared. data control_optional_brand_present: NonEmptyStr? = Present { value: "tailnet.example" } @@ -159,10 +158,6 @@ fn optional_data_row_cases() -> List { NativeEmissionCase { identity: "optional_data_row_red_absent_answers_absent", held: control_optional_brand_value(d: control_optional_brand_absent) == "" - }, - NativeEmissionCase { - identity: "optional_named_coproduct_row_keeps_its_wire_policy", - held: collision_row_value(o: collision_wrapped_row) == 7 } ] } @@ -202,8 +197,7 @@ data native_emission_expected_identities: List = [ "filter_guard_receipt_red_empty_tag_short_circuits", "claim_driver_filesystem_absent_path_read_is_refused", "optional_data_row_present_answers_its_value", - "optional_data_row_red_absent_answers_absent", - "optional_named_coproduct_row_keeps_its_wire_policy" + "optional_data_row_red_absent_answers_absent" ] fn native_emission_cases() -> List { diff --git a/dag/gunbc/instruments/native_emission_controls_optional_collision.dag b/dag/gunbc/instruments/native_emission_controls_optional_collision.dag deleted file mode 100644 index f7aa3b7ad11..00000000000 --- a/dag/gunbc/instruments/native_emission_controls_optional_collision.dag +++ /dev/null @@ -1,21 +0,0 @@ -module gunbc.instruments.native_emission_controls_optional_collision - -import std.types { Int } - -// A NON-KERNEL COPRODUCT THAT HAPPENS TO BE NAMED Optional, for the collision case in -// gunbc.instruments.native_emission_controls. Its data row has no `?`, so it must be serialized under -// its own wire policy like any other declared coproduct. A serializer that chose the native option by -// the parent's LEAF SPELLING would spell this row as its bare payload, which the emitted enum cannot -// parse (review on gunbc#13202). -type Optional - = CollisionWrapped { value: Int } - | CollisionEmpty - -data collision_wrapped_row: Optional = CollisionWrapped { value: 7 } - -fn collision_row_value(o: Optional) -> Int { - match o { - CollisionWrapped { value: v } => v - CollisionEmpty => 0 - } -} diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index c4d1cd2620e..5a7f9798dd4 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -16864,6 +16864,11 @@ fn data_row_type_forbids_deserialize(type_node: Node, emit_info: EmitGraphInfo, type_expr_reaches_sealed_carrier(n: type_node, emit_info: emit_info, source_indices: source_indices, seen: empty_map()) } +// Named rather than inlined because `if x == Variant {` parses as a record literal in .dag. +fn data_row_declares_optional(type_node: Node) -> Bool { + type_node.return_cardinality == CardOptional +} + fn emit_data_def_body(type_node: Node, value: Node, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo, needs_rc: Bool) -> String { let raw_ty_str = render_rust_type(n: type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices, emit_info: emit_info) let type_name = authored_name_at(source_indices: scope.type_env.source_indices, node: type_node) @@ -16922,7 +16927,7 @@ fn emit_data_def_body(type_node: Node, value: Node, registry: Map true _ => false } { concat(" ", emit_typed_expr(texpr: value, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024)) } else if has_nested_records_node(n: type_node, source_indices: scope.type_env.source_indices) && !data_value_has_cross_refs(value: value) && !data_row_type_forbids_deserialize(type_node: type_node, emit_info: emit_info, source_indices: scope.type_env.source_indices) { - let row_json = if type_node.return_cardinality == CardOptional { + let row_json = if data_row_declares_optional(type_node: type_node) { emit_declared_optional_row_json(value: value, inner_type_name: authored_name_at(source_indices: scope.type_env.source_indices, node: type_node), source_indices: scope.type_env.source_indices, variant_wire: emit_info.data_variant_wire_spellings) } else { emit_data_value_json(value: value, source_indices: scope.type_env.source_indices, variant_wire: emit_info.data_variant_wire_spellings) From 804fe940ed5477ea5dc3c17326d952b823a0e68c Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 10:25:56 +0000 Subject: [PATCH 24/69] G (review): regenerated mirrors for the declared-cardinality serializer Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit.rs | 185 ++++++++++++--------- src/v1/stage0/src/v1_compiler_emit_rust.rs | 39 ++++- 2 files changed, 140 insertions(+), 84 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 0a7eecce4c7..66f21a48172 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -1023,29 +1023,63 @@ pub fn emit_data_fields_json( ) } -pub fn emit_optional_data_value_json( +pub fn emit_declared_optional_row_json( value: Rc, + inner_type_name: String, source_indices: Rc>>, variant_wire: Rc>>, ) -> Rc { - match value.children.clone().first().cloned() { - std::option::Option::None => Rc::new(EmitterOutcome::Emitted { - json: "null".to_string(), - }), - Some(payload_field) => { - if ((value.children.clone().len() as i64) == 1) { - emit_data_value_json( - crate::v1_std_core::field_init_node_value(payload_field.clone()), - source_indices.clone(), - variant_wire.clone(), - ) - } else { - Rc::new(EmitterOutcome::Refused { - reason: "an Optional variant literal carries more than its one payload field" - .to_string(), - }) - } + match (*value.expr_data.clone()).clone() { + ExprData::ExprLiteral { ref value, .. } + if matches!(value.as_ref(), LiteralValue::LitNull) => + { + let LiteralValue::LitNull = value.as_ref() else { + unreachable!() + }; + Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }) } + ExprData::ExprRecordLit { + parent_enum: pe, .. + } => match pe.clone() { + Some(parent) => { + if (crate::v1_std_core::qualified_last_segment(parent.clone()) + == crate::v1_std_core::qualified_last_segment(inner_type_name.clone())) + { + emit_data_value_json( + value.clone(), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + match value.children.clone().first().cloned() { + std::option::Option::None => Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }), + Some(payload_field) => { + if ((value.children.clone().len() as i64) == 1) { + emit_data_value_json( + crate::v1_std_core::field_init_node_value( + payload_field.clone(), + ), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat("an optional row's present literal carries ".to_string(), crate::v1_compiler_emit_core_support::to_string((value.children.clone().len() as i64))), " fields; the option's present arm carries exactly its payload".to_string()), +}) + } + } + } + } + } + std::option::Option::None => { + emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()) + } + }, + _ => emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()), } } @@ -1124,25 +1158,27 @@ pub fn emit_data_value_json( } ExprData::ExprRecordLit { parent_enum: pe, .. - } => { - match pe.clone() { - Some(parent) => { - if (crate::v1_std_core::qualified_last_segment(parent.clone()) - == "Optional".to_string()) - { - emit_optional_data_value_json( - value.clone(), - source_indices.clone(), - variant_wire.clone(), - ) - } else { - match crate::v1_std_core::record_lit_type_name_at(value.clone(), source_indices.clone()) { - std::option::Option::None => Rc::new(EmitterOutcome::Refused { - reason: v1_rt::concat(v1_rt::concat("variant record literal with parent coproduct ".to_string(), parent.clone()), " carries no authored head name to key the wire-spelling index".to_string()), -}), - Some(head) => { - let key = v1_rt::concat(v1_rt::concat(parent.clone(), ".".to_string()), crate::v1_std_core::qualified_last_segment(head.clone())); -match v1_rt::map_get(&variant_wire, key.clone()) { + } => match pe.clone() { + Some(parent) => match crate::v1_std_core::record_lit_type_name_at( + value.clone(), + source_indices.clone(), + ) { + std::option::Option::None => Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat( + v1_rt::concat( + "variant record literal with parent coproduct ".to_string(), + parent.clone(), + ), + " carries no authored head name to key the wire-spelling index" + .to_string(), + ), + }), + Some(head) => { + let key = v1_rt::concat( + v1_rt::concat(parent.clone(), ".".to_string()), + crate::v1_std_core::qualified_last_segment(head.clone()), + ); + match v1_rt::map_get(&variant_wire, key.clone()) { std::option::Option::None => Rc::new(EmitterOutcome::Refused { reason: v1_rt::concat(v1_rt::concat("no wire spelling indexed for ".to_string(), key.clone()), ": the index covers every coproduct declared in the emission closure it was built from, so this parent is outside that closure".to_string()), }), @@ -1151,11 +1187,11 @@ match v1_rt::map_get(&variant_wire, key.clone()) { reason: r.clone(), }), DataVariantWireSpelling::DataVariantUntagged => if ((value.children.clone().len() as i64) == 0) { - Rc::new(EmitterOutcome::Emitted { + Rc::new(EmitterOutcome::Emitted { json: "null".to_string(), }) - } else { - match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wire.clone())).clone() { + } else { + match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wire.clone())).clone() { JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => Rc::new(EmitterOutcome::Refused { reason: r.clone(), }), @@ -1163,18 +1199,18 @@ match v1_rt::map_get(&variant_wire, key.clone()) { json: v1_rt::concat(v1_rt::concat("{".to_string(), ps.clone().join(&", ".to_string())), "}".to_string()), }), } - }, + }, DataVariantWireSpelling::DataVariantBareString { tag: t, .. } => if ((value.children.clone().len() as i64) == 0) { - Rc::new(EmitterOutcome::Emitted { + Rc::new(EmitterOutcome::Emitted { json: v1_rt::concat(v1_rt::concat("\"".to_string(), crate::v1_compiler_emit_core_support::escape_json_string(t.clone())), "\"".to_string()), }) - } else { - Rc::new(EmitterOutcome::Refused { + } else { + Rc::new(EmitterOutcome::Refused { reason: v1_rt::concat(v1_rt::concat("variant ".to_string(), key.clone()), " carries fields under a StringVariant wire policy, which is nullary-only; the type-side emission of the parent coproduct refuses it too".to_string()), }) - }, + }, DataVariantWireSpelling::DataVariantInternalTagged { tag_field: tf, tag: t, .. } => { - let tag_piece = v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("\"".to_string(), crate::v1_compiler_emit_core_support::escape_json_string(tf.clone())), "\": \"".to_string()), crate::v1_compiler_emit_core_support::escape_json_string(t.clone())), "\"".to_string()); + let tag_piece = v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("\"".to_string(), crate::v1_compiler_emit_core_support::escape_json_string(tf.clone())), "\": \"".to_string()), crate::v1_compiler_emit_core_support::escape_json_string(t.clone())), "\"".to_string()); match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wire.clone())).clone() { JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => Rc::new(EmitterOutcome::Refused { reason: r.clone(), @@ -1186,42 +1222,39 @@ match (*emit_data_fields_json(value.clone(), source_indices.clone(), variant_wir }, }, } -}, -} - } } - std::option::Option::None => { - if ((value.children.clone().len() as i64) == 0) { - Rc::new(EmitterOutcome::Emitted { - json: "null".to_string(), - }) - } else { - match (*emit_data_fields_json( - value.clone(), - source_indices.clone(), - variant_wire.clone(), - )) - .clone() - { - JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => { - Rc::new(EmitterOutcome::Refused { reason: r.clone() }) - } - JsonFragmentsAccum::FragmentsAccumulated { pieces: ps, .. } => { - Rc::new(EmitterOutcome::Emitted { - json: v1_rt::concat( - v1_rt::concat( - "{".to_string(), - ps.clone().join(&", ".to_string()), - ), - "}".to_string(), + }, + std::option::Option::None => { + if ((value.children.clone().len() as i64) == 0) { + Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }) + } else { + match (*emit_data_fields_json( + value.clone(), + source_indices.clone(), + variant_wire.clone(), + )) + .clone() + { + JsonFragmentsAccum::FragmentsRefused { reason: r, .. } => { + Rc::new(EmitterOutcome::Refused { reason: r.clone() }) + } + JsonFragmentsAccum::FragmentsAccumulated { pieces: ps, .. } => { + Rc::new(EmitterOutcome::Emitted { + json: v1_rt::concat( + v1_rt::concat( + "{".to_string(), + ps.clone().join(&", ".to_string()), ), - }) - } + "}".to_string(), + ), + }) } } } } - } + }, ExprData::ExprVar { binding_kind: _, .. } => Rc::new(EmitterOutcome::Emitted { diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 7e6431d4400..73c884786b2 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -174,13 +174,13 @@ use crate::v1_compiler_emit::ShellResultChannel::{ pub use crate::v1_compiler_emit::{ bind_operation_transport, child_from_key, compute_service_fields, effective_operation_transport, emit_bin_op_symbol, emit_container, emit_data_value_json, - emit_error_expr, emit_ident, emit_keyed_container_type, emit_keyword, emit_lambda, - emit_lambda_params, emit_let_binding, emit_let_binding_annotated, emit_list_lit_expr, - emit_literal, emit_node_type, emit_null_coalesce, emit_return, emit_shared_expr, - emit_shared_tco_expr, emit_simple_expr, emit_string_literal, emit_typed_cast_shared, - emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, escape_rust_interp_text, - extract_modifier_names, has_nested_records_node, has_service_items, is_null_coalesce, - is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, + emit_declared_optional_row_json, emit_error_expr, emit_ident, emit_keyed_container_type, + emit_keyword, emit_lambda, emit_lambda_params, emit_let_binding, emit_let_binding_annotated, + emit_list_lit_expr, emit_literal, emit_node_type, emit_null_coalesce, emit_return, + emit_shared_expr, emit_shared_tco_expr, emit_simple_expr, emit_string_literal, + emit_typed_cast_shared, emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, + escape_rust_interp_text, extract_modifier_names, has_nested_records_node, has_service_items, + is_null_coalesce, is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, lookup_item_by_identity, module_emit_scope, order_typed_call_args_from_semantics, render_node_type, render_tuple_parts, rust_literal_for_pattern, scope_after_expr, seed_bindings, service_fallback_transport, service_field_ctors, service_field_decls, @@ -38952,6 +38952,10 @@ pub fn data_row_type_forbids_deserialize( ) } +pub fn data_row_declares_optional(type_node: Rc) -> bool { + (type_node.return_cardinality.clone() == Cardinality::CardOptional) +} + pub fn emit_data_def_body( type_node: Rc, value: Rc, @@ -39138,10 +39142,29 @@ pub fn emit_data_def_body( scope.type_env.clone().source_indices.clone(), )) { - match (*crate::v1_compiler_emit::emit_data_value_json(value.clone(), scope.type_env.clone().source_indices.clone(), emit_info.data_variant_wire_spellings.clone())).clone() { + { + let row_json = if data_row_declares_optional(type_node.clone()) { + crate::v1_compiler_emit::emit_declared_optional_row_json( + value.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + type_node.clone(), + ), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + } else { + crate::v1_compiler_emit::emit_data_value_json( + value.clone(), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + }; + match (*row_json.clone()).clone() { EmitterOutcome::Refused { reason: r, .. } => v1_rt::concat(v1_rt::concat(" compile_error!(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(r.clone())), "\")".to_string()), EmitterOutcome::Emitted { json: json_str, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(" serde_json::from_str(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(json_str.clone())), "\")\n".to_string()), " .expect(\"valid data definition\")".to_string()), } + } } else { { let is_map = crate::v1_compiler_infer_types::node_is_keyed_collection( From 01f9489fc7fec0e8c61dafa0fb9eabe7b9a84d4e Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 10:27:38 +0000 Subject: [PATCH 25/69] C4: complexity arg_name_at as a match; C5: refuse a bare T body under a declared T? return Co-Authored-By: Claude Opus 5.5 (1M context) --- ...f_host_equality_admission_witness_test.dag | 22 +++++++++++ src/v1/04_infer.dag | 37 ++++++++++++++++++- src/v1/complexity.dag | 7 ++-- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 5ec116fd70a..6da5848fd5c 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -137,3 +137,25 @@ test fn explicit_match_on_optional_stays_admitted() -> Bool { test fn optional_compared_with_optional_stays_admitted() -> Bool { eq_admitted(source: optionality_both_optional_green_source) } + +// C5, THE SAME CLASS AT THE DECLARED RETURN: a fn declared `-> T?` whose body produces a bare T. No +// declared coercion lifts T into T?, and the Rust emission refused it (E0308, gunbc.running_release_ +// identity running_release_member_string). The red is a bare-Int body under `-> Int?`; the controls +// are the explicit present spelling and the absent spelling, which the arm must not widen into. +data return_lift_red_source: String = "module ret_probe_lift\nfn f(x: Int) -> Int? { x }\n" + +data return_explicit_present_green_source: String = "module ret_probe_present\nfn f(x: Int) -> Int? { Present { value: x } }\n" + +data return_absent_green_source: String = "module ret_probe_absent\nfn f(x: Int) -> Int? { none }\n" + +test fn required_body_at_optional_return_refuses_blocking() -> Bool { + eq_blocking_count(source: return_lift_red_source, wanted: "DeclaredTypeNotInhabited") == 1 +} + +test fn explicit_present_return_stays_admitted() -> Bool { + eq_admitted(source: return_explicit_present_green_source) +} + +test fn absent_return_stays_admitted() -> Bool { + eq_admitted(source: return_absent_green_source) +} diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 47d4a610cfd..409923957bf 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4340,6 +4340,40 @@ fn declared_type_inhabitance(obligation: DeclaredTypeObligation, scope: InferSco // Required and non-generic: a type variable may be instantiated at an Optional, and an unresolved // or erased declared identity is not a Required fact, so those stay with their own arms. // +// THE MIRROR, AT THE DECLARED RETURN (gunbc.recurring_failure_mode optional_compared_with_required_value, +// class C5). A fn declared `-> T?` whose body produces a bare T was accepted: no declared coercion +// lifts T into T? (DESIGN 4, 2026-09-26), and the Rust emission refused it as E0308 `expected +// Option, found T` (gunbc.running_release_identity running_release_member_string). It is judged +// here at the declared return only, the position the ruling names; a bare T bound to a T? PARAMETER +// or field is a different position whose population was not measured by this change and is not +// claimed. The none / Absent presence spellings produce an optional and never reach this arm. +fn position_is_declared_return(position: DeclaredTypePosition) -> Bool { + match position { + PositionDeclaredReturn => true + _ => false + } +} + +fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: InferScope) -> Bool { + let source_indices = scope.type_env.source_indices + let declared_name = authored_name_at(source_indices: source_indices, node: declared) + let produced_name = authored_name_at(source_indices: source_indices, node: produced) + let produced_carries_optional = produced.return_cardinality == CardOptional + || qualified_last_segment(name: produced_name) == "Optional" + let produced_is_generic = (produced.params |> count) > 0 || match produced.inferred { + Present { value: TypeVariable { id: _ } } => true + Present { value: inferred } => is_compiler_error(inferred: inferred) + _ => true + } + declared.return_cardinality == CardOptional + && !produced_carries_optional + && !produced_is_generic + && produced_name != "" + && declared_name != "" + && !type_node_is_callable(n: declared) + && !type_node_is_callable(n: produced) +} + fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: InferScope) -> Bool { let source_indices = scope.type_env.source_indices let declared_name = authored_name_at(source_indices: source_indices, node: declared) @@ -4379,7 +4413,8 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: // DIRECTED fact about a declared position, which is what the obligation carries. // fn optional_at_required_obligation_diags(obligation: DeclaredTypeObligation, scope: InferScope) -> List { - if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) { + if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) + || (position_is_declared_return(position: obligation.position) && required_produced_at_optional_declared(declared: obligation.declared, produced: obligation.produced, scope: scope)) { [make_error_node( diagnostic: DeclaredTypeNotInhabited { position: declared_type_position_label(position: obligation.position, subject: obligation.subject), diff --git a/src/v1/complexity.dag b/src/v1/complexity.dag index 579a8d93b46..05889ba4242 100644 --- a/src/v1/complexity.dag +++ b/src/v1/complexity.dag @@ -297,10 +297,9 @@ fn parser_state_arg_expr(call_node: Node, state_param: ParserStateParam, si: Map } else { let idx = pair.first let arg_node = pair.second - let matches_state = if arg_name_at(n: arg_node, source_indices: si) != "" { - arg_name_at(n: arg_node, source_indices: si) == state_param.name - } else { - idx == state_param.index + let matches_state = match arg_name_at(n: arg_node, source_indices: si) { + Present { value: label } => if label != "" { label == state_param.name } else { idx == state_param.index } + Absent => idx == state_param.index } if matches_state { Present { value: arg_value(n: arg_node) } From bcec7d70d87bd2423857a616ada78c2a3cb5c3e2 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 10:46:35 +0000 Subject: [PATCH 26/69] C5: compiler-error test in the seed's established spelling Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/04_infer.dag | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 409923957bf..ca6c1d14e5b 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4360,11 +4360,13 @@ fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: let produced_name = authored_name_at(source_indices: source_indices, node: produced) let produced_carries_optional = produced.return_cardinality == CardOptional || qualified_last_segment(name: produced_name) == "Optional" - let produced_is_generic = (produced.params |> count) > 0 || match produced.inferred { - Present { value: TypeVariable { id: _ } } => true - Present { value: inferred } => is_compiler_error(inferred: inferred) - _ => true - } + let produced_is_generic = (produced.params |> count) > 0 + || produced.inferred == none + || is_compiler_error(inferred: produced.inferred.value) + || match produced.inferred { + Present { value: TypeVariable { id: _ } } => true + _ => false + } declared.return_cardinality == CardOptional && !produced_carries_optional && !produced_is_generic From c8ac46574ff67e59b36e798d4a1a62bc665695dd Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 11:07:39 +0000 Subject: [PATCH 27/69] C4/C5: regenerated infer and complexity mirrors (seed is a fixed point under both walls) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_complexity.rs | 18 +-- src/v1/stage0/src/v1_compiler_infer.rs | 126 ++++++++++++++++---- 2 files changed, 115 insertions(+), 29 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_complexity.rs b/src/v1/stage0/src/v1_compiler_complexity.rs index 2a80e63b5e6..b24523cf490 100644 --- a/src/v1/stage0/src/v1_compiler_complexity.rs +++ b/src/v1/stage0/src/v1_compiler_complexity.rs @@ -519,15 +519,15 @@ pub fn parser_state_arg_expr( let idx = pair.0.clone(); let arg_node = pair.1.clone(); let matches_state = - if (crate::v1_std_core::arg_name_at(arg_node.clone(), si.clone()) - .as_deref() - != Some("".to_string()).as_deref()) - { - (crate::v1_std_core::arg_name_at(arg_node.clone(), si.clone()) - .as_deref() - == Some(state_param.name.clone()).as_deref()) - } else { - (idx.clone() == state_param.index.clone()) + match crate::v1_std_core::arg_name_at(arg_node.clone(), si.clone()) { + Some(label) => { + if (label.clone() != "".to_string()) { + (label.clone() == state_param.name.clone()) + } else { + (idx.clone() == state_param.index.clone()) + } + } + std::option::Option::None => (idx.clone() == state_param.index.clone()), }; if matches_state.clone() { Some(crate::v1_std_core::arg_value(arg_node.clone())) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index d0595364414..b08221880a2 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -280,10 +280,10 @@ use crate::v1_std_core::CompilerDiagnostic::{ AlgebraApplicationEvidenceUnavailable, AmbiguousReference, BareNoneNotAdmittedByFieldType, CallArgumentDuplicate, CallArgumentNameUnknown, CallNamedArgOnFunctionValue, CallPositionalDeficit, CallPositionalSurplus, ConstructorCallAdmissionRefused, - EqualityMemberUnjudgeable, EqualityOnFunctionMember, FieldNotFound, - FrontierOccurrenceBudgetExceeded, InternalError, MethodExistenceFrontierAdmitted, - MethodExistenceUndecided, MethodNotFound, MissingField, OptionalCastNotEliminated, - ReceiverTypeUnestablished, ServiceConfigReferenceJudgmentDeferred, + EqualityMemberUnjudgeable, EqualityOnFunctionMember, EqualityOptionalityMismatch, + FieldNotFound, FrontierOccurrenceBudgetExceeded, InternalError, + MethodExistenceFrontierAdmitted, MethodExistenceUndecided, MethodNotFound, MissingField, + OptionalCastNotEliminated, ReceiverTypeUnestablished, ServiceConfigReferenceJudgmentDeferred, SiblingOperandEffectOrderUndetermined, SoleConstructorViolation, TextRepresentationUnidentifiedAtBoundary, TypeArgumentArityMismatch, TypeMismatch, TypeParameterInValuePosition, UnlistedVariantValueUse, UnresolvedType, VariantCollision, @@ -5020,6 +5020,22 @@ pub fn equality_operand_is_presence_literal( } } +pub fn equality_operand_is_optional( + n: Rc, + source_indices: Rc>>, +) -> bool { + match n.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: rt, .. }) => { + ((rt.return_cardinality.clone() == Cardinality::CardOptional) + || ((crate::v1_std_core::qualified_last_segment( + crate::v1_std_core::authored_name_at(source_indices.clone(), rt.clone()), + ) == "Optional".to_string()) + && ((rt.children.clone().len() as i64) == 1))) + } + _ => false, + } +} + pub fn equality_admission_refusal_diag( r: Rc, span: Rc, @@ -5095,18 +5111,32 @@ pub fn equality_admission_diags( { Rc::new(vec![]) } else { - match equality_operand_admission( - lt.clone(), - scope.clone(), - v1_rt::rc_empty_map::(), - 0, - ) { - Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( - equality_admission_refusal_diag(r.clone(), span.clone()), - scope.module_name.clone(), - )]), - std::option::Option::None => match equality_operand_admission( - rt.clone(), + if (equality_operand_is_optional(left_typed.clone(), source_indices.clone()) + != equality_operand_is_optional( + right_typed.clone(), + source_indices.clone(), + )) + { + { + let side = if equality_operand_is_optional( + left_typed.clone(), + source_indices.clone(), + ) { + "left".to_string() + } else { + "right".to_string() + }; + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::EqualityOptionalityMismatch { + optional_side: side.clone(), + span: span.clone(), + }), + scope.module_name.clone(), + )]) + } + } else { + match equality_operand_admission( + lt.clone(), scope.clone(), v1_rt::rc_empty_map::(), 0, @@ -5115,8 +5145,19 @@ pub fn equality_admission_diags( equality_admission_refusal_diag(r.clone(), span.clone()), scope.module_name.clone(), )]), - std::option::Option::None => Rc::new(vec![]), - }, + std::option::Option::None => match equality_operand_admission( + rt.clone(), + scope.clone(), + v1_rt::rc_empty_map::(), + 0, + ) { + Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( + equality_admission_refusal_diag(r.clone(), span.clone()), + scope.module_name.clone(), + )]), + std::option::Option::None => Rc::new(vec![]), + }, + } } } } @@ -6109,6 +6150,45 @@ pub fn declared_type_inhabitance( } } +pub fn position_is_declared_return(position: DeclaredTypePosition) -> bool { + match position.clone() { + DeclaredTypePosition::PositionDeclaredReturn => true, + _ => false, + } +} + +pub fn required_produced_at_optional_declared( + declared: Rc, + produced: Rc, + scope: Rc, +) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), declared.clone()); + let produced_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), produced.clone()); + let produced_carries_optional = ((produced.return_cardinality.clone() + == Cardinality::CardOptional) + || (crate::v1_std_core::qualified_last_segment(produced_name.clone()) + == "Optional".to_string())); + let produced_is_generic = (((((produced.params.clone().len() as i64) > 0) + || (produced.inferred.clone() == std::option::Option::None)) + || crate::v1_std_core::is_compiler_error(produced.inferred.clone().clone().unwrap())) + || match produced.inferred.clone().as_deref().cloned() { + Some(InferredNode::TypeVariable { id: _, .. }) => true, + _ => false, + }); + (((((((declared.return_cardinality.clone() == Cardinality::CardOptional) + && !produced_carries_optional.clone()) + && !produced_is_generic.clone()) + && (produced_name.clone() != "".to_string())) + && (declared_name.clone() != "".to_string())) + && !type_node_is_callable(declared.clone())) + && !type_node_is_callable(produced.clone())) + } +} + pub fn optional_produced_at_required_declared( declared: Rc, produced: Rc, @@ -6156,11 +6236,17 @@ pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, ) -> Rc>> { - if optional_produced_at_required_declared( + if (optional_produced_at_required_declared( obligation.declared.clone(), obligation.produced.clone(), scope.clone(), - ) { + ) || (position_is_declared_return(obligation.position.clone()) + && required_produced_at_optional_declared( + obligation.declared.clone(), + obligation.produced.clone(), + scope.clone(), + ))) + { Rc::new(vec![crate::v1_std_core::make_error_node( Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { position: declared_type_position_label( From b0cf68a2515072223d0d3b343e0df6c9eb304574 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 12:03:23 +0000 Subject: [PATCH 28/69] C5: one declared-optional authority for both cardinality directions; match-arm RED added Co-Authored-By: Claude Opus 5.5 (1M context) --- ...f_host_equality_admission_witness_test.dag | 6 +++++ src/v1/04_infer.dag | 23 +++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 6da5848fd5c..adbf7beb87e 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -159,3 +159,9 @@ test fn explicit_present_return_stays_admitted() -> Bool { test fn absent_return_stays_admitted() -> Bool { eq_admitted(source: return_absent_green_source) } + +data return_lift_match_arm_red_source: String = "module ret_probe_arm\nfn g(s: String) -> String? {\n match s {\n \"a\" => s\n _ => none\n }\n}\n" + +test fn required_arm_at_optional_return_refuses_blocking() -> Bool { + eq_blocking_count(source: return_lift_match_arm_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 +} diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index ca6c1d14e5b..bc19463105a 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4340,6 +4340,20 @@ fn declared_type_inhabitance(obligation: DeclaredTypeObligation, scope: InferSco // Required and non-generic: a type variable may be instantiated at an Optional, and an unresolved // or erased declared identity is not a Required fact, so those stay with their own arms. // +// ONE ANSWER TO "IS THIS DECLARED TYPE OPTIONAL", read by both cardinality directions. Optionality +// lives in two representations (declared_type_conformance_note class 1): CardOptional on the node or +// its alias-peeled form, or the nominal Optional coproduct a `-> T?` return arrives as. The leaf-name +// arm is the pre-existing authority this function always used, not a new one; it is part of the +// bare-name identity debt routed to 2K's identity-keying lane. +fn declared_type_carries_optional(declared: Node, scope: InferScope) -> Bool { + let source_indices = scope.type_env.source_indices + let declared_peeled = peel_nominal_alias_identity(n: declared, env: scope.type_env, module_name: scope.module_name) + declared.return_cardinality == CardOptional + || declared_peeled.return_cardinality == CardOptional + || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared)) == "Optional" + || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared_peeled)) == "Optional" +} + // THE MIRROR, AT THE DECLARED RETURN (gunbc.recurring_failure_mode optional_compared_with_required_value, // class C5). A fn declared `-> T?` whose body produces a bare T was accepted: no declared coercion // lifts T into T? (DESIGN 4, 2026-09-26), and the Rust emission refused it as E0308 `expected @@ -4367,7 +4381,7 @@ fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: Present { value: TypeVariable { id: _ } } => true _ => false } - declared.return_cardinality == CardOptional + declared_type_carries_optional(declared: declared, scope: scope) && !produced_carries_optional && !produced_is_generic && produced_name != "" @@ -4386,13 +4400,8 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: Present { value: TypeVariable { id: _ } } => true _ => false } - let declared_peeled = peel_nominal_alias_identity(n: declared, env: scope.type_env, module_name: scope.module_name) - let declared_carries_optional = declared.return_cardinality == CardOptional - || declared_peeled.return_cardinality == CardOptional - || qualified_last_segment(name: declared_name) == "Optional" - || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared_peeled)) == "Optional" produced_carries_optional - && !declared_carries_optional + && !declared_type_carries_optional(declared: declared, scope: scope) && !declared_is_generic && declared_name != "" && !type_node_is_callable(n: declared) From 8be9316666e902e3dd400703360751da362ca254 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 12:25:04 +0000 Subject: [PATCH 29/69] Revert "C5: one declared-optional authority for both cardinality directions; match-arm RED added" This reverts commit b0cf68a2515072223d0d3b343e0df6c9eb304574. --- ...f_host_equality_admission_witness_test.dag | 6 ----- src/v1/04_infer.dag | 23 ++++++------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index adbf7beb87e..6da5848fd5c 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -159,9 +159,3 @@ test fn explicit_present_return_stays_admitted() -> Bool { test fn absent_return_stays_admitted() -> Bool { eq_admitted(source: return_absent_green_source) } - -data return_lift_match_arm_red_source: String = "module ret_probe_arm\nfn g(s: String) -> String? {\n match s {\n \"a\" => s\n _ => none\n }\n}\n" - -test fn required_arm_at_optional_return_refuses_blocking() -> Bool { - eq_blocking_count(source: return_lift_match_arm_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 -} diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index bc19463105a..ca6c1d14e5b 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4340,20 +4340,6 @@ fn declared_type_inhabitance(obligation: DeclaredTypeObligation, scope: InferSco // Required and non-generic: a type variable may be instantiated at an Optional, and an unresolved // or erased declared identity is not a Required fact, so those stay with their own arms. // -// ONE ANSWER TO "IS THIS DECLARED TYPE OPTIONAL", read by both cardinality directions. Optionality -// lives in two representations (declared_type_conformance_note class 1): CardOptional on the node or -// its alias-peeled form, or the nominal Optional coproduct a `-> T?` return arrives as. The leaf-name -// arm is the pre-existing authority this function always used, not a new one; it is part of the -// bare-name identity debt routed to 2K's identity-keying lane. -fn declared_type_carries_optional(declared: Node, scope: InferScope) -> Bool { - let source_indices = scope.type_env.source_indices - let declared_peeled = peel_nominal_alias_identity(n: declared, env: scope.type_env, module_name: scope.module_name) - declared.return_cardinality == CardOptional - || declared_peeled.return_cardinality == CardOptional - || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared)) == "Optional" - || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared_peeled)) == "Optional" -} - // THE MIRROR, AT THE DECLARED RETURN (gunbc.recurring_failure_mode optional_compared_with_required_value, // class C5). A fn declared `-> T?` whose body produces a bare T was accepted: no declared coercion // lifts T into T? (DESIGN 4, 2026-09-26), and the Rust emission refused it as E0308 `expected @@ -4381,7 +4367,7 @@ fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: Present { value: TypeVariable { id: _ } } => true _ => false } - declared_type_carries_optional(declared: declared, scope: scope) + declared.return_cardinality == CardOptional && !produced_carries_optional && !produced_is_generic && produced_name != "" @@ -4400,8 +4386,13 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: Present { value: TypeVariable { id: _ } } => true _ => false } + let declared_peeled = peel_nominal_alias_identity(n: declared, env: scope.type_env, module_name: scope.module_name) + let declared_carries_optional = declared.return_cardinality == CardOptional + || declared_peeled.return_cardinality == CardOptional + || qualified_last_segment(name: declared_name) == "Optional" + || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared_peeled)) == "Optional" produced_carries_optional - && !declared_type_carries_optional(declared: declared, scope: scope) + && !declared_carries_optional && !declared_is_generic && declared_name != "" && !type_node_is_callable(n: declared) From 11f3ddc0824e6ceae44846c5b998d652b953248a Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 12:25:04 +0000 Subject: [PATCH 30/69] Revert "C5: compiler-error test in the seed's established spelling" This reverts commit bcec7d70d87bd2423857a616ada78c2a3cb5c3e2. --- src/v1/04_infer.dag | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index ca6c1d14e5b..409923957bf 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4360,13 +4360,11 @@ fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: let produced_name = authored_name_at(source_indices: source_indices, node: produced) let produced_carries_optional = produced.return_cardinality == CardOptional || qualified_last_segment(name: produced_name) == "Optional" - let produced_is_generic = (produced.params |> count) > 0 - || produced.inferred == none - || is_compiler_error(inferred: produced.inferred.value) - || match produced.inferred { - Present { value: TypeVariable { id: _ } } => true - _ => false - } + let produced_is_generic = (produced.params |> count) > 0 || match produced.inferred { + Present { value: TypeVariable { id: _ } } => true + Present { value: inferred } => is_compiler_error(inferred: inferred) + _ => true + } declared.return_cardinality == CardOptional && !produced_carries_optional && !produced_is_generic From 99998f12243bdd2f8002ce964c91ec548162eaa9 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 12:25:04 +0000 Subject: [PATCH 31/69] Revert "C4: complexity arg_name_at as a match; C5: refuse a bare T body under a declared T? return" This reverts commit 01f9489fc7fec0e8c61dafa0fb9eabe7b9a84d4e. --- ...f_host_equality_admission_witness_test.dag | 22 ----------- src/v1/04_infer.dag | 37 +------------------ src/v1/complexity.dag | 7 ++-- 3 files changed, 5 insertions(+), 61 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 6da5848fd5c..5ec116fd70a 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -137,25 +137,3 @@ test fn explicit_match_on_optional_stays_admitted() -> Bool { test fn optional_compared_with_optional_stays_admitted() -> Bool { eq_admitted(source: optionality_both_optional_green_source) } - -// C5, THE SAME CLASS AT THE DECLARED RETURN: a fn declared `-> T?` whose body produces a bare T. No -// declared coercion lifts T into T?, and the Rust emission refused it (E0308, gunbc.running_release_ -// identity running_release_member_string). The red is a bare-Int body under `-> Int?`; the controls -// are the explicit present spelling and the absent spelling, which the arm must not widen into. -data return_lift_red_source: String = "module ret_probe_lift\nfn f(x: Int) -> Int? { x }\n" - -data return_explicit_present_green_source: String = "module ret_probe_present\nfn f(x: Int) -> Int? { Present { value: x } }\n" - -data return_absent_green_source: String = "module ret_probe_absent\nfn f(x: Int) -> Int? { none }\n" - -test fn required_body_at_optional_return_refuses_blocking() -> Bool { - eq_blocking_count(source: return_lift_red_source, wanted: "DeclaredTypeNotInhabited") == 1 -} - -test fn explicit_present_return_stays_admitted() -> Bool { - eq_admitted(source: return_explicit_present_green_source) -} - -test fn absent_return_stays_admitted() -> Bool { - eq_admitted(source: return_absent_green_source) -} diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 409923957bf..47d4a610cfd 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4340,40 +4340,6 @@ fn declared_type_inhabitance(obligation: DeclaredTypeObligation, scope: InferSco // Required and non-generic: a type variable may be instantiated at an Optional, and an unresolved // or erased declared identity is not a Required fact, so those stay with their own arms. // -// THE MIRROR, AT THE DECLARED RETURN (gunbc.recurring_failure_mode optional_compared_with_required_value, -// class C5). A fn declared `-> T?` whose body produces a bare T was accepted: no declared coercion -// lifts T into T? (DESIGN 4, 2026-09-26), and the Rust emission refused it as E0308 `expected -// Option, found T` (gunbc.running_release_identity running_release_member_string). It is judged -// here at the declared return only, the position the ruling names; a bare T bound to a T? PARAMETER -// or field is a different position whose population was not measured by this change and is not -// claimed. The none / Absent presence spellings produce an optional and never reach this arm. -fn position_is_declared_return(position: DeclaredTypePosition) -> Bool { - match position { - PositionDeclaredReturn => true - _ => false - } -} - -fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: InferScope) -> Bool { - let source_indices = scope.type_env.source_indices - let declared_name = authored_name_at(source_indices: source_indices, node: declared) - let produced_name = authored_name_at(source_indices: source_indices, node: produced) - let produced_carries_optional = produced.return_cardinality == CardOptional - || qualified_last_segment(name: produced_name) == "Optional" - let produced_is_generic = (produced.params |> count) > 0 || match produced.inferred { - Present { value: TypeVariable { id: _ } } => true - Present { value: inferred } => is_compiler_error(inferred: inferred) - _ => true - } - declared.return_cardinality == CardOptional - && !produced_carries_optional - && !produced_is_generic - && produced_name != "" - && declared_name != "" - && !type_node_is_callable(n: declared) - && !type_node_is_callable(n: produced) -} - fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: InferScope) -> Bool { let source_indices = scope.type_env.source_indices let declared_name = authored_name_at(source_indices: source_indices, node: declared) @@ -4413,8 +4379,7 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: // DIRECTED fact about a declared position, which is what the obligation carries. // fn optional_at_required_obligation_diags(obligation: DeclaredTypeObligation, scope: InferScope) -> List { - if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) - || (position_is_declared_return(position: obligation.position) && required_produced_at_optional_declared(declared: obligation.declared, produced: obligation.produced, scope: scope)) { + if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) { [make_error_node( diagnostic: DeclaredTypeNotInhabited { position: declared_type_position_label(position: obligation.position, subject: obligation.subject), diff --git a/src/v1/complexity.dag b/src/v1/complexity.dag index 05889ba4242..579a8d93b46 100644 --- a/src/v1/complexity.dag +++ b/src/v1/complexity.dag @@ -297,9 +297,10 @@ fn parser_state_arg_expr(call_node: Node, state_param: ParserStateParam, si: Map } else { let idx = pair.first let arg_node = pair.second - let matches_state = match arg_name_at(n: arg_node, source_indices: si) { - Present { value: label } => if label != "" { label == state_param.name } else { idx == state_param.index } - Absent => idx == state_param.index + let matches_state = if arg_name_at(n: arg_node, source_indices: si) != "" { + arg_name_at(n: arg_node, source_indices: si) == state_param.name + } else { + idx == state_param.index } if matches_state { Present { value: arg_value(n: arg_node) } From b05cab4001fff064c2737a12586bd70d73515f32 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 12:25:09 +0000 Subject: [PATCH 32/69] C4: complexity arg_name_at comparisons as a match (re-applied without C5) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/complexity.dag | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/v1/complexity.dag b/src/v1/complexity.dag index 579a8d93b46..05889ba4242 100644 --- a/src/v1/complexity.dag +++ b/src/v1/complexity.dag @@ -297,10 +297,9 @@ fn parser_state_arg_expr(call_node: Node, state_param: ParserStateParam, si: Map } else { let idx = pair.first let arg_node = pair.second - let matches_state = if arg_name_at(n: arg_node, source_indices: si) != "" { - arg_name_at(n: arg_node, source_indices: si) == state_param.name - } else { - idx == state_param.index + let matches_state = match arg_name_at(n: arg_node, source_indices: si) { + Present { value: label } => if label != "" { label == state_param.name } else { idx == state_param.index } + Absent => idx == state_param.index } if matches_state { Present { value: arg_value(n: arg_node) } From 648e348e4666769fffe526d427b63a252b7985a0 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 12:51:09 +0000 Subject: [PATCH 33/69] C4: regenerated infer mirror without C5 (seed is a fixed point under the T?==T wall) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 49 ++------------------------ 1 file changed, 2 insertions(+), 47 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index b08221880a2..3b76efc09ac 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -6150,45 +6150,6 @@ pub fn declared_type_inhabitance( } } -pub fn position_is_declared_return(position: DeclaredTypePosition) -> bool { - match position.clone() { - DeclaredTypePosition::PositionDeclaredReturn => true, - _ => false, - } -} - -pub fn required_produced_at_optional_declared( - declared: Rc, - produced: Rc, - scope: Rc, -) -> bool { - { - let source_indices = scope.type_env.clone().source_indices.clone(); - let declared_name = - crate::v1_std_core::authored_name_at(source_indices.clone(), declared.clone()); - let produced_name = - crate::v1_std_core::authored_name_at(source_indices.clone(), produced.clone()); - let produced_carries_optional = ((produced.return_cardinality.clone() - == Cardinality::CardOptional) - || (crate::v1_std_core::qualified_last_segment(produced_name.clone()) - == "Optional".to_string())); - let produced_is_generic = (((((produced.params.clone().len() as i64) > 0) - || (produced.inferred.clone() == std::option::Option::None)) - || crate::v1_std_core::is_compiler_error(produced.inferred.clone().clone().unwrap())) - || match produced.inferred.clone().as_deref().cloned() { - Some(InferredNode::TypeVariable { id: _, .. }) => true, - _ => false, - }); - (((((((declared.return_cardinality.clone() == Cardinality::CardOptional) - && !produced_carries_optional.clone()) - && !produced_is_generic.clone()) - && (produced_name.clone() != "".to_string())) - && (declared_name.clone() != "".to_string())) - && !type_node_is_callable(declared.clone())) - && !type_node_is_callable(produced.clone())) - } -} - pub fn optional_produced_at_required_declared( declared: Rc, produced: Rc, @@ -6236,17 +6197,11 @@ pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, ) -> Rc>> { - if (optional_produced_at_required_declared( + if optional_produced_at_required_declared( obligation.declared.clone(), obligation.produced.clone(), scope.clone(), - ) || (position_is_declared_return(obligation.position.clone()) - && required_produced_at_optional_declared( - obligation.declared.clone(), - obligation.produced.clone(), - scope.clone(), - ))) - { + ) { Rc::new(vec![crate::v1_std_core::make_error_node( Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { position: declared_type_position_label( From 83003858bbd38739dc006fecf0b327564994020b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 13:00:40 +0000 Subject: [PATCH 34/69] C5: re-apply the declared-return mirror predicate and REDs (diagnosis in progress) Co-Authored-By: Claude Opus 5.5 (1M context) --- ...f_host_equality_admission_witness_test.dag | 28 +++++++++ src/v1/04_infer.dag | 60 ++++++++++++++++--- 2 files changed, 81 insertions(+), 7 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 5ec116fd70a..adbf7beb87e 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -137,3 +137,31 @@ test fn explicit_match_on_optional_stays_admitted() -> Bool { test fn optional_compared_with_optional_stays_admitted() -> Bool { eq_admitted(source: optionality_both_optional_green_source) } + +// C5, THE SAME CLASS AT THE DECLARED RETURN: a fn declared `-> T?` whose body produces a bare T. No +// declared coercion lifts T into T?, and the Rust emission refused it (E0308, gunbc.running_release_ +// identity running_release_member_string). The red is a bare-Int body under `-> Int?`; the controls +// are the explicit present spelling and the absent spelling, which the arm must not widen into. +data return_lift_red_source: String = "module ret_probe_lift\nfn f(x: Int) -> Int? { x }\n" + +data return_explicit_present_green_source: String = "module ret_probe_present\nfn f(x: Int) -> Int? { Present { value: x } }\n" + +data return_absent_green_source: String = "module ret_probe_absent\nfn f(x: Int) -> Int? { none }\n" + +test fn required_body_at_optional_return_refuses_blocking() -> Bool { + eq_blocking_count(source: return_lift_red_source, wanted: "DeclaredTypeNotInhabited") == 1 +} + +test fn explicit_present_return_stays_admitted() -> Bool { + eq_admitted(source: return_explicit_present_green_source) +} + +test fn absent_return_stays_admitted() -> Bool { + eq_admitted(source: return_absent_green_source) +} + +data return_lift_match_arm_red_source: String = "module ret_probe_arm\nfn g(s: String) -> String? {\n match s {\n \"a\" => s\n _ => none\n }\n}\n" + +test fn required_arm_at_optional_return_refuses_blocking() -> Bool { + eq_blocking_count(source: return_lift_match_arm_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 +} diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 47d4a610cfd..bc19463105a 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4340,6 +4340,56 @@ fn declared_type_inhabitance(obligation: DeclaredTypeObligation, scope: InferSco // Required and non-generic: a type variable may be instantiated at an Optional, and an unresolved // or erased declared identity is not a Required fact, so those stay with their own arms. // +// ONE ANSWER TO "IS THIS DECLARED TYPE OPTIONAL", read by both cardinality directions. Optionality +// lives in two representations (declared_type_conformance_note class 1): CardOptional on the node or +// its alias-peeled form, or the nominal Optional coproduct a `-> T?` return arrives as. The leaf-name +// arm is the pre-existing authority this function always used, not a new one; it is part of the +// bare-name identity debt routed to 2K's identity-keying lane. +fn declared_type_carries_optional(declared: Node, scope: InferScope) -> Bool { + let source_indices = scope.type_env.source_indices + let declared_peeled = peel_nominal_alias_identity(n: declared, env: scope.type_env, module_name: scope.module_name) + declared.return_cardinality == CardOptional + || declared_peeled.return_cardinality == CardOptional + || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared)) == "Optional" + || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared_peeled)) == "Optional" +} + +// THE MIRROR, AT THE DECLARED RETURN (gunbc.recurring_failure_mode optional_compared_with_required_value, +// class C5). A fn declared `-> T?` whose body produces a bare T was accepted: no declared coercion +// lifts T into T? (DESIGN 4, 2026-09-26), and the Rust emission refused it as E0308 `expected +// Option, found T` (gunbc.running_release_identity running_release_member_string). It is judged +// here at the declared return only, the position the ruling names; a bare T bound to a T? PARAMETER +// or field is a different position whose population was not measured by this change and is not +// claimed. The none / Absent presence spellings produce an optional and never reach this arm. +fn position_is_declared_return(position: DeclaredTypePosition) -> Bool { + match position { + PositionDeclaredReturn => true + _ => false + } +} + +fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: InferScope) -> Bool { + let source_indices = scope.type_env.source_indices + let declared_name = authored_name_at(source_indices: source_indices, node: declared) + let produced_name = authored_name_at(source_indices: source_indices, node: produced) + let produced_carries_optional = produced.return_cardinality == CardOptional + || qualified_last_segment(name: produced_name) == "Optional" + let produced_is_generic = (produced.params |> count) > 0 + || produced.inferred == none + || is_compiler_error(inferred: produced.inferred.value) + || match produced.inferred { + Present { value: TypeVariable { id: _ } } => true + _ => false + } + declared_type_carries_optional(declared: declared, scope: scope) + && !produced_carries_optional + && !produced_is_generic + && produced_name != "" + && declared_name != "" + && !type_node_is_callable(n: declared) + && !type_node_is_callable(n: produced) +} + fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: InferScope) -> Bool { let source_indices = scope.type_env.source_indices let declared_name = authored_name_at(source_indices: source_indices, node: declared) @@ -4350,13 +4400,8 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: Present { value: TypeVariable { id: _ } } => true _ => false } - let declared_peeled = peel_nominal_alias_identity(n: declared, env: scope.type_env, module_name: scope.module_name) - let declared_carries_optional = declared.return_cardinality == CardOptional - || declared_peeled.return_cardinality == CardOptional - || qualified_last_segment(name: declared_name) == "Optional" - || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared_peeled)) == "Optional" produced_carries_optional - && !declared_carries_optional + && !declared_type_carries_optional(declared: declared, scope: scope) && !declared_is_generic && declared_name != "" && !type_node_is_callable(n: declared) @@ -4379,7 +4424,8 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: // DIRECTED fact about a declared position, which is what the obligation carries. // fn optional_at_required_obligation_diags(obligation: DeclaredTypeObligation, scope: InferScope) -> List { - if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) { + if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) + || (position_is_declared_return(position: obligation.position) && required_produced_at_optional_declared(declared: obligation.declared, produced: obligation.produced, scope: scope)) { [make_error_node( diagnostic: DeclaredTypeNotInhabited { position: declared_type_position_label(position: obligation.position, subject: obligation.subject), From 3039c7627a88d6273c6b5003762f4aca5f43f85b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 14:00:48 +0000 Subject: [PATCH 35/69] C5: a resolved type with no inferred field is concrete, not generic Diagnosed with a never-pushed instrument: the declared return's produced type was correct (Primitive(Int) under Optional), so infer does not adopt the expected type. The predicate exempted every produced type whose inferred field was unset, which is every resolved type node. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/04_infer.dag | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index bc19463105a..aa11523215c 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4375,8 +4375,7 @@ fn required_produced_at_optional_declared(declared: Node, produced: Node, scope: let produced_carries_optional = produced.return_cardinality == CardOptional || qualified_last_segment(name: produced_name) == "Optional" let produced_is_generic = (produced.params |> count) > 0 - || produced.inferred == none - || is_compiler_error(inferred: produced.inferred.value) + || (produced.inferred != none && is_compiler_error(inferred: produced.inferred.value)) || match produced.inferred { Present { value: TypeVariable { id: _ } } => true _ => false From f7c380c75ec5682e8d7760343e0452ccd782b6b1 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 14:22:15 +0000 Subject: [PATCH 36/69] C5: regenerated infer mirror (seed is a fixed point under the return wall) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 89 +++++++++++++++++++++----- 1 file changed, 72 insertions(+), 17 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 3b76efc09ac..414b6a95523 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -6150,6 +6150,68 @@ pub fn declared_type_inhabitance( } } +pub fn declared_type_carries_optional(declared: Rc, scope: Rc) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( + declared.clone(), + scope.type_env.clone(), + scope.module_name.clone(), + ); + ((((declared.return_cardinality.clone() == Cardinality::CardOptional) + || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared.clone(), + )) == "Optional".to_string())) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared_peeled.clone(), + )) == "Optional".to_string())) + } +} + +pub fn position_is_declared_return(position: DeclaredTypePosition) -> bool { + match position.clone() { + DeclaredTypePosition::PositionDeclaredReturn => true, + _ => false, + } +} + +pub fn required_produced_at_optional_declared( + declared: Rc, + produced: Rc, + scope: Rc, +) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), declared.clone()); + let produced_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), produced.clone()); + let produced_carries_optional = ((produced.return_cardinality.clone() + == Cardinality::CardOptional) + || (crate::v1_std_core::qualified_last_segment(produced_name.clone()) + == "Optional".to_string())); + let produced_is_generic = ((((produced.params.clone().len() as i64) > 0) + || ((produced.inferred.clone() != std::option::Option::None) + && crate::v1_std_core::is_compiler_error( + produced.inferred.clone().clone().unwrap(), + ))) + || match produced.inferred.clone().as_deref().cloned() { + Some(InferredNode::TypeVariable { id: _, .. }) => true, + _ => false, + }); + ((((((declared_type_carries_optional(declared.clone(), scope.clone()) + && !produced_carries_optional.clone()) + && !produced_is_generic.clone()) + && (produced_name.clone() != "".to_string())) + && (declared_name.clone() != "".to_string())) + && !type_node_is_callable(declared.clone())) + && !type_node_is_callable(produced.clone())) + } +} + pub fn optional_produced_at_required_declared( declared: Rc, produced: Rc, @@ -6170,21 +6232,8 @@ pub fn optional_produced_at_required_declared( Some(InferredNode::TypeVariable { id: _, .. }) => true, _ => false, }); - let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( - declared.clone(), - scope.type_env.clone(), - scope.module_name.clone(), - ); - let declared_carries_optional = ((((declared.return_cardinality.clone() - == Cardinality::CardOptional) - || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) - || (crate::v1_std_core::qualified_last_segment(declared_name.clone()) - == "Optional".to_string())) - || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( - source_indices.clone(), - declared_peeled.clone(), - )) == "Optional".to_string())); - ((((((produced_carries_optional.clone() && !declared_carries_optional.clone()) + ((((((produced_carries_optional.clone() + && !declared_type_carries_optional(declared.clone(), scope.clone())) && !declared_is_generic.clone()) && (declared_name.clone() != "".to_string())) && !type_node_is_callable(declared.clone())) @@ -6197,11 +6246,17 @@ pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, ) -> Rc>> { - if optional_produced_at_required_declared( + if (optional_produced_at_required_declared( obligation.declared.clone(), obligation.produced.clone(), scope.clone(), - ) { + ) || (position_is_declared_return(obligation.position.clone()) + && required_produced_at_optional_declared( + obligation.declared.clone(), + obligation.produced.clone(), + scope.clone(), + ))) + { Rc::new(vec![crate::v1_std_core::make_error_node( Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { position: declared_type_position_label( From 58c46691e499423ba3a7563ca8114a2134fd238e Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 14:50:32 +0000 Subject: [PATCH 37/69] C5: regenerated infer mirror over merged main Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 227 +++++++++++++++---------- 1 file changed, 134 insertions(+), 93 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 9eb37ef8f2c..4478e5c9bcc 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -280,10 +280,10 @@ use crate::v1_std_core::CompilerDiagnostic::{ AlgebraApplicationEvidenceUnavailable, AmbiguousReference, BareNoneNotAdmittedByFieldType, CallArgumentDuplicate, CallArgumentNameUnknown, CallNamedArgOnFunctionValue, CallPositionalDeficit, CallPositionalSurplus, ConstructorCallAdmissionRefused, - EqualityMemberUnjudgeable, EqualityOnFunctionMember, FieldNotFound, - FrontierOccurrenceBudgetExceeded, InternalError, MethodExistenceFrontierAdmitted, - MethodExistenceUndecided, MethodNotFound, MissingField, OptionalCastNotEliminated, - ReceiverTypeUnestablished, ServiceConfigReferenceJudgmentDeferred, + EqualityMemberUnjudgeable, EqualityOnFunctionMember, EqualityOptionalityMismatch, + FieldNotFound, FrontierOccurrenceBudgetExceeded, InternalError, + MethodExistenceFrontierAdmitted, MethodExistenceUndecided, MethodNotFound, MissingField, + OptionalCastNotEliminated, ReceiverTypeUnestablished, ServiceConfigReferenceJudgmentDeferred, SiblingOperandEffectOrderUndetermined, SoleConstructorViolation, TextRepresentationUnidentifiedAtBoundary, TypeArgumentArityMismatch, TypeMismatch, TypeParameterInValuePosition, UnlistedVariantValueUse, UnresolvedType, VariantCollision, @@ -1923,7 +1923,6 @@ pub fn explicit_return_conformance_diags( "".to_string(), declared.clone(), expression_value_type(returned.clone()), - returned.clone(), returned.span.clone(), scope.clone(), )) @@ -2146,7 +2145,6 @@ pub fn declared_type_conformance_diags( subject: String, declared: Rc, produced: Rc, - produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2169,7 +2167,6 @@ pub fn declared_type_conformance_diags( subject.clone(), declared.clone(), produced.clone(), - produced_by.clone(), span.clone(), scope.clone(), ), @@ -2181,7 +2178,6 @@ pub fn declared_type_conformance_diags_core( subject: String, declared: Rc, produced: Rc, - produced_by: Rc, span: Rc, scope: Rc, ) -> Rc>> { @@ -2189,7 +2185,7 @@ pub fn declared_type_conformance_diags_core( let si = scope.type_env.clone().source_indices.clone(); let both_ground = (conformance_ground_type(declared.clone(), si.clone()) && conformance_ground_type(produced.clone(), si.clone())); - let cardinality_diags = optional_at_required_value_obligation_diags( + let cardinality_diags = optional_at_required_obligation_diags( Rc::new(DeclaredTypeObligation { position: position.clone(), subject: subject.clone(), @@ -2197,7 +2193,6 @@ pub fn declared_type_conformance_diags_core( produced: produced.clone(), span: span.clone(), }), - produced_by.clone(), scope.clone(), ); if ((cardinality_diags.clone().len() as i64) > 0) { @@ -5025,6 +5020,22 @@ pub fn equality_operand_is_presence_literal( } } +pub fn equality_operand_is_optional( + n: Rc, + source_indices: Rc>>, +) -> bool { + match n.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: rt, .. }) => { + ((rt.return_cardinality.clone() == Cardinality::CardOptional) + || ((crate::v1_std_core::qualified_last_segment( + crate::v1_std_core::authored_name_at(source_indices.clone(), rt.clone()), + ) == "Optional".to_string()) + && ((rt.children.clone().len() as i64) == 1))) + } + _ => false, + } +} + pub fn equality_admission_refusal_diag( r: Rc, span: Rc, @@ -5100,18 +5111,32 @@ pub fn equality_admission_diags( { Rc::new(vec![]) } else { - match equality_operand_admission( - lt.clone(), - scope.clone(), - v1_rt::rc_empty_map::(), - 0, - ) { - Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( - equality_admission_refusal_diag(r.clone(), span.clone()), - scope.module_name.clone(), - )]), - std::option::Option::None => match equality_operand_admission( - rt.clone(), + if (equality_operand_is_optional(left_typed.clone(), source_indices.clone()) + != equality_operand_is_optional( + right_typed.clone(), + source_indices.clone(), + )) + { + { + let side = if equality_operand_is_optional( + left_typed.clone(), + source_indices.clone(), + ) { + "left".to_string() + } else { + "right".to_string() + }; + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::EqualityOptionalityMismatch { + optional_side: side.clone(), + span: span.clone(), + }), + scope.module_name.clone(), + )]) + } + } else { + match equality_operand_admission( + lt.clone(), scope.clone(), v1_rt::rc_empty_map::(), 0, @@ -5120,8 +5145,19 @@ pub fn equality_admission_diags( equality_admission_refusal_diag(r.clone(), span.clone()), scope.module_name.clone(), )]), - std::option::Option::None => Rc::new(vec![]), - }, + std::option::Option::None => match equality_operand_admission( + rt.clone(), + scope.clone(), + v1_rt::rc_empty_map::(), + 0, + ) { + Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( + equality_admission_refusal_diag(r.clone(), span.clone()), + scope.module_name.clone(), + )]), + std::option::Option::None => Rc::new(vec![]), + }, + } } } } @@ -6114,6 +6150,68 @@ pub fn declared_type_inhabitance( } } +pub fn declared_type_carries_optional(declared: Rc, scope: Rc) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( + declared.clone(), + scope.type_env.clone(), + scope.module_name.clone(), + ); + ((((declared.return_cardinality.clone() == Cardinality::CardOptional) + || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared.clone(), + )) == "Optional".to_string())) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared_peeled.clone(), + )) == "Optional".to_string())) + } +} + +pub fn position_is_declared_return(position: DeclaredTypePosition) -> bool { + match position.clone() { + DeclaredTypePosition::PositionDeclaredReturn => true, + _ => false, + } +} + +pub fn required_produced_at_optional_declared( + declared: Rc, + produced: Rc, + scope: Rc, +) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), declared.clone()); + let produced_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), produced.clone()); + let produced_carries_optional = ((produced.return_cardinality.clone() + == Cardinality::CardOptional) + || (crate::v1_std_core::qualified_last_segment(produced_name.clone()) + == "Optional".to_string())); + let produced_is_generic = ((((produced.params.clone().len() as i64) > 0) + || ((produced.inferred.clone() != std::option::Option::None) + && crate::v1_std_core::is_compiler_error( + produced.inferred.clone().clone().unwrap(), + ))) + || match produced.inferred.clone().as_deref().cloned() { + Some(InferredNode::TypeVariable { id: _, .. }) => true, + _ => false, + }); + ((((((declared_type_carries_optional(declared.clone(), scope.clone()) + && !produced_carries_optional.clone()) + && !produced_is_generic.clone()) + && (produced_name.clone() != "".to_string())) + && (declared_name.clone() != "".to_string())) + && !type_node_is_callable(declared.clone())) + && !type_node_is_callable(produced.clone())) + } +} + pub fn optional_produced_at_required_declared( declared: Rc, produced: Rc, @@ -6134,21 +6232,8 @@ pub fn optional_produced_at_required_declared( Some(InferredNode::TypeVariable { id: _, .. }) => true, _ => false, }); - let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( - declared.clone(), - scope.type_env.clone(), - scope.module_name.clone(), - ); - let declared_carries_optional = ((((declared.return_cardinality.clone() - == Cardinality::CardOptional) - || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) - || (crate::v1_std_core::qualified_last_segment(declared_name.clone()) - == "Optional".to_string())) - || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( - source_indices.clone(), - declared_peeled.clone(), - )) == "Optional".to_string())); - ((((((produced_carries_optional.clone() && !declared_carries_optional.clone()) + ((((((produced_carries_optional.clone() + && !declared_type_carries_optional(declared.clone(), scope.clone())) && !declared_is_generic.clone()) && (declared_name.clone() != "".to_string())) && !type_node_is_callable(declared.clone())) @@ -6157,62 +6242,21 @@ pub fn optional_produced_at_required_declared( } } -pub fn expr_value_is_index_access(mut __tco_loop_e: Rc) -> bool { - loop { - #[allow(unused_mut)] - let mut e = __tco_loop_e; - match (*e.expr_data.clone()).clone() { - ExprData::ExprIndex => { - break true; - } - ExprData::ExprLet => match crate::v1_std_core::let_body(e.clone()) { - Some(body) => { - let __tco_0 = body.clone(); - __tco_loop_e = __tco_0; - continue; - } - std::option::Option::None => { - break false; - } - }, - ExprData::ExprBlock => match e.children.clone().last().cloned() { - Some(tail) => { - let __tco_0 = tail.clone(); - __tco_loop_e = __tco_0; - continue; - } - std::option::Option::None => { - break false; - } - }, - _ => { - break false; - } - } - } -} - -pub fn optional_at_required_value_obligation_diags( - obligation: Rc, - produced_by: Rc, - scope: Rc, -) -> Rc>> { - if expr_value_is_index_access(produced_by.clone()) { - Rc::new(vec![]) - } else { - optional_at_required_obligation_diags(obligation.clone(), scope.clone()) - } -} - pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, ) -> Rc>> { - if optional_produced_at_required_declared( + if (optional_produced_at_required_declared( obligation.declared.clone(), obligation.produced.clone(), scope.clone(), - ) { + ) || (position_is_declared_return(obligation.position.clone()) + && required_produced_at_optional_declared( + obligation.declared.clone(), + obligation.produced.clone(), + scope.clone(), + ))) + { Rc::new(vec![crate::v1_std_core::make_error_node( Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { position: declared_type_position_label( @@ -14596,7 +14640,6 @@ crate::v1_compiler_infer_types::resolve_type_variables_from_template(t.clone(), let_name.clone(), declared.clone(), produced_value_type.clone(), - val_typed.clone(), val_expr.span.clone(), scope.clone(), ); @@ -17283,13 +17326,13 @@ let field_type_diags = match field_declared_type.clone() { let field_cardinality_diags = if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) } else { - optional_at_required_value_obligation_diags(Rc::new(DeclaredTypeObligation { + optional_at_required_obligation_diags(Rc::new(DeclaredTypeObligation { position: DeclaredTypePosition::PositionRecordLiteralField, subject: fi_name.clone(), declared: expected_node.clone(), produced: got_node.clone(), span: ar_typed.span.clone(), -}), ar_typed.clone(), scope.clone()) +}), scope.clone()) }; if direct_call_formal_has_unbound_type_variable(field_conformance_type.clone()) { Rc::new(vec![]) @@ -22979,7 +23022,6 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), declared_return_type_node(item.clone()), crate::v1_compiler_infer_types::resolved_type(body_typed.clone()), - body_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), @@ -23087,7 +23129,6 @@ pub fn infer_item(item: Rc, scope: Rc) -> Rc "".to_string(), item.type_annotation.clone().clone().unwrap(), expression_value_type(val_typed.clone()), - val_typed.clone(), item.body.clone().clone().unwrap().span.clone(), scope.clone(), ), From e86fbba4742bf1c69832e28abaa6695dd0d2450d Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sun, 4 Oct 2026 15:13:26 +0000 Subject: [PATCH 38/69] C5: running_release_member_string answers Present { value: s } for a JSON string member The one corpus site the declared-return wall refuses (CI floor, 2685 modules): the arm returned a bare String under -> String?. Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/running_release_identity.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dag/gunbc/running_release_identity.dag b/dag/gunbc/running_release_identity.dag index 4d432ac265b..8c7c95ff0c0 100644 --- a/dag/gunbc/running_release_identity.dag +++ b/dag/gunbc/running_release_identity.dag @@ -137,7 +137,7 @@ fn running_release_member_string(lookup: JsonMemberLookup) -> String? { match lookup { JsonMemberFound { value: v } => match v { - JsonString { value: s } => s + JsonString { value: s } => Present { value: s } JsonNull => Absent JsonBool { value: _ } => Absent JsonNumber { lexeme: _ } => Absent From 034324d44edfdf9701fc448a4797efc4b869c0f1 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 17:25:19 +0000 Subject: [PATCH 39/69] G: regenerate emit mirrors over merged main (batch 2; fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit.rs | 60 ++++++++++++++++++++++ src/v1/stage0/src/v1_compiler_emit_rust.rs | 58 +++++++++++++++------ 2 files changed, 102 insertions(+), 16 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 2f04a101181..ef6d61be01d 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -1023,6 +1023,66 @@ pub fn emit_data_fields_json( ) } +pub fn emit_declared_optional_row_json( + value: Rc, + inner_type_name: String, + source_indices: Rc>>, + variant_wire: Rc>>, +) -> Rc { + match (*value.expr_data.clone()).clone() { + ExprData::ExprLiteral { ref value, .. } + if matches!(value.as_ref(), LiteralValue::LitNull) => + { + let LiteralValue::LitNull = value.as_ref() else { + unreachable!() + }; + Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }) + } + ExprData::ExprRecordLit { + parent_enum: pe, .. + } => match pe.clone() { + Some(parent) => { + if (crate::v1_std_core::qualified_last_segment(parent.clone()) + == crate::v1_std_core::qualified_last_segment(inner_type_name.clone())) + { + emit_data_value_json( + value.clone(), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + match value.children.clone().first().cloned() { + std::option::Option::None => Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }), + Some(payload_field) => { + if ((value.children.clone().len() as i64) == 1) { + emit_data_value_json( + crate::v1_std_core::field_init_node_value( + payload_field.clone(), + ), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat("an optional row's present literal carries ".to_string(), crate::v1_compiler_emit_core_support::to_string((value.children.clone().len() as i64))), " fields; the option's present arm carries exactly its payload".to_string()), +}) + } + } + } + } + } + std::option::Option::None => { + emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()) + } + }, + _ => emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()), + } +} + pub fn emit_data_value_json( value: Rc, source_indices: Rc>>, diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index d6596625f51..e93315f3490 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -186,13 +186,13 @@ use crate::v1_compiler_emit::ShellResultChannel::{ pub use crate::v1_compiler_emit::{ bind_operation_transport, child_from_key, compute_service_fields, effective_operation_transport, emit_bin_op_symbol, emit_container, emit_data_value_json, - emit_error_expr, emit_ident, emit_keyed_container_type, emit_keyword, emit_lambda, - emit_lambda_params, emit_let_binding, emit_let_binding_annotated, emit_list_lit_expr, - emit_literal, emit_node_type, emit_null_coalesce, emit_return, emit_shared_expr, - emit_shared_tco_expr, emit_simple_expr, emit_string_literal, emit_typed_cast_shared, - emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, escape_rust_interp_text, - extract_modifier_names, has_nested_records_node, has_service_items, is_null_coalesce, - is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, + emit_declared_optional_row_json, emit_error_expr, emit_ident, emit_keyed_container_type, + emit_keyword, emit_lambda, emit_lambda_params, emit_let_binding, emit_let_binding_annotated, + emit_list_lit_expr, emit_literal, emit_node_type, emit_null_coalesce, emit_return, + emit_shared_expr, emit_shared_tco_expr, emit_simple_expr, emit_string_literal, + emit_typed_cast_shared, emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, + escape_rust_interp_text, extract_modifier_names, has_nested_records_node, has_service_items, + is_null_coalesce, is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, lookup_item_by_identity, module_emit_scope, order_typed_call_args_from_semantics, render_node_type, render_tuple_parts, rust_literal_for_pattern, scope_after_expr, seed_bindings, service_fallback_transport, service_field_ctors, service_field_decls, @@ -39656,18 +39656,21 @@ pub fn emit_data_def( annotation_type_node.clone(), scope.type_env.clone().source_indices.clone(), ) { - crate::v1_compiler_coercion::coerce_primitive_type( - crate::v1_compiler_coercion::type_reference_realization( - annotation_type_node.clone(), + rust_carrier_optional_wrap( + annotation_type_node.clone(), + crate::v1_compiler_coercion::coerce_primitive_type( + crate::v1_compiler_coercion::type_reference_realization( + annotation_type_node.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + annotation_type_node.clone(), + ), + RenderTarget::Rust, + ), crate::v1_std_core::authored_name_at( scope.type_env.clone().source_indices.clone(), annotation_type_node.clone(), ), - RenderTarget::Rust, - ), - crate::v1_std_core::authored_name_at( - scope.type_env.clone().source_indices.clone(), - annotation_type_node.clone(), ), ) } else { @@ -39822,6 +39825,10 @@ pub fn data_row_type_forbids_deserialize( ) } +pub fn data_row_declares_optional(type_node: Rc) -> bool { + (type_node.return_cardinality.clone() == Cardinality::CardOptional) +} + pub fn emit_data_def_body( type_node: Rc, value: Rc, @@ -40008,10 +40015,29 @@ pub fn emit_data_def_body( scope.type_env.clone().source_indices.clone(), )) { - match (*crate::v1_compiler_emit::emit_data_value_json(value.clone(), scope.type_env.clone().source_indices.clone(), emit_info.data_variant_wire_spellings.clone())).clone() { + { + let row_json = if data_row_declares_optional(type_node.clone()) { + crate::v1_compiler_emit::emit_declared_optional_row_json( + value.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + type_node.clone(), + ), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + } else { + crate::v1_compiler_emit::emit_data_value_json( + value.clone(), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + }; + match (*row_json.clone()).clone() { EmitterOutcome::Refused { reason: r, .. } => v1_rt::concat(v1_rt::concat(" compile_error!(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(r.clone())), "\")".to_string()), EmitterOutcome::Emitted { json: json_str, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(" serde_json::from_str(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(json_str.clone())), "\")\n".to_string()), " .expect(\"valid data definition\")".to_string()), } + } } else { { let is_map = crate::v1_compiler_infer_types::node_is_keyed_collection( From efa68745e2e01acac8f5e4cf3be28271bcbb25ba Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 17:38:59 +0000 Subject: [PATCH 40/69] G (review 76684): exercise the inner-type arm; stop claiming collision coverage Adds optional_data_row_inner_type_literal_is_a_value_of_t: a ControlShape? row whose literal's parent is ControlShape. A wrong inner-type comparison unwraps it to a bare payload that fails at run time. The emit comment no longer claims a collision case (that RED is lane 2K's) and states that the multi-field refusal has no run-time case. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../instruments/native_emission_controls.dag | 28 ++++++++++++++++++- src/v1/05_emit.dag | 6 +++- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index 62ac6097b98..2cd7573f14a 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -265,6 +265,27 @@ fn control_optional_brand_value(d: NonEmptyStr?) -> String { } } +// THE INNER-TYPE ARM: the literal's parent IS the declared inner type, so the row holds a value of T +// and is spelled as one. ControlShape's present variant carries one field, so a wrong inner-type +// comparison would unwrap `ControlCircle { radius: 3 }` to a bare `3`, which the emitted enum cannot +// parse -- the row would fail at run time rather than answer 3. +type ControlShape + = ControlCircle { radius: Int } + | ControlNoShape + +data control_optional_shape_row: ControlShape? = ControlCircle { radius: 3 } + +fn control_optional_shape_radius(s: ControlShape?) -> Int { + match s { + Present { value: shape } => + match shape { + ControlCircle { radius: r } => r + ControlNoShape => 0 + } + Absent => 0 - 1 + } +} + fn optional_data_row_cases() -> List { [ NativeEmissionCase { @@ -274,6 +295,10 @@ fn optional_data_row_cases() -> List { NativeEmissionCase { identity: "optional_data_row_red_absent_answers_absent", held: control_optional_brand_value(d: control_optional_brand_absent) == "" + }, + NativeEmissionCase { + identity: "optional_data_row_inner_type_literal_is_a_value_of_t", + held: control_optional_shape_radius(s: control_optional_shape_row) == 3 } ] } @@ -432,7 +457,8 @@ data native_emission_expected_identities: List = [ "fold_constructor_init_red_negative_switches_arm", "fold_constructor_init_red_empty_keeps_init", "optional_data_row_present_answers_its_value", - "optional_data_row_red_absent_answers_absent" + "optional_data_row_red_absent_answers_absent", + "optional_data_row_inner_type_literal_is_a_value_of_t" ] fn native_emission_cases() -> List { diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index a5ca238e94d..3285e4bfd19 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -502,7 +502,11 @@ fn emit_data_fields_json(value: Node, source_indices: Map, // Within an optional row, a variant literal whose parent IS the declared inner type is a value of T // and is spelled as one; any other one-field variant literal is the option's present arm and is // unwrapped to its payload. Control: gunbc.instruments.native_emission_controls optional_data_row_cases -// and its Optional-named collision case. +// -- the present and absent rows, and a row whose literal's parent is the declared inner type (a wrong +// inner-type comparison would unwrap it and fail at run time). A coproduct merely NAMED Optional +// cannot be emitted at all today (type rendering decides host-option by leaf name); that case is +// lane 2K's RED, not covered here. The more-than-one-field refusal emits a compile_error! and has no +// run-time case. fn emit_declared_optional_row_json(value: Node, inner_type_name: String, source_indices: Map, variant_wire: Map) -> EmitterOutcome { match value.expr_data { ExprLiteral { value: LitNull } => Emitted { json: "null" } From d21f6ecc96d52d8c1a9bcb2c186c411e086ca833 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 18:21:39 +0000 Subject: [PATCH 41/69] G (review 76684): a bare inner-type literal under T? refuses instead of being spelled The inner-type arm realized an implicit T -> T? lift that no declared coercion admits; the typed-expression path for the same row already emits it bare and rustc refuses it (E0308, measured with the added control). The arm now refuses with a located reason; the control that exposed it is withdrawn since its literal is exactly what is refused. Co-Authored-By: Claude Opus 5.5 (1M context) --- .../instruments/native_emission_controls.dag | 28 +------------------ src/v1/05_emit.dag | 18 ++++++------ 2 files changed, 11 insertions(+), 35 deletions(-) diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index 2cd7573f14a..62ac6097b98 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -265,27 +265,6 @@ fn control_optional_brand_value(d: NonEmptyStr?) -> String { } } -// THE INNER-TYPE ARM: the literal's parent IS the declared inner type, so the row holds a value of T -// and is spelled as one. ControlShape's present variant carries one field, so a wrong inner-type -// comparison would unwrap `ControlCircle { radius: 3 }` to a bare `3`, which the emitted enum cannot -// parse -- the row would fail at run time rather than answer 3. -type ControlShape - = ControlCircle { radius: Int } - | ControlNoShape - -data control_optional_shape_row: ControlShape? = ControlCircle { radius: 3 } - -fn control_optional_shape_radius(s: ControlShape?) -> Int { - match s { - Present { value: shape } => - match shape { - ControlCircle { radius: r } => r - ControlNoShape => 0 - } - Absent => 0 - 1 - } -} - fn optional_data_row_cases() -> List { [ NativeEmissionCase { @@ -295,10 +274,6 @@ fn optional_data_row_cases() -> List { NativeEmissionCase { identity: "optional_data_row_red_absent_answers_absent", held: control_optional_brand_value(d: control_optional_brand_absent) == "" - }, - NativeEmissionCase { - identity: "optional_data_row_inner_type_literal_is_a_value_of_t", - held: control_optional_shape_radius(s: control_optional_shape_row) == 3 } ] } @@ -457,8 +432,7 @@ data native_emission_expected_identities: List = [ "fold_constructor_init_red_negative_switches_arm", "fold_constructor_init_red_empty_keeps_init", "optional_data_row_present_answers_its_value", - "optional_data_row_red_absent_answers_absent", - "optional_data_row_inner_type_literal_is_a_value_of_t" + "optional_data_row_red_absent_answers_absent" ] fn native_emission_cases() -> List { diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index 3285e4bfd19..0cc367a52bd 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -499,14 +499,16 @@ fn emit_data_fields_json(value: Node, source_indices: Map, // this only for a row whose declared type carries CardOptional, so an unrelated coproduct that happens // to be NAMED Optional keeps its own wire policy (review on gunbc#13202: a leaf-name test here was a // second, unrostered authority that would have serialized such a coproduct as null or a bare payload). -// Within an optional row, a variant literal whose parent IS the declared inner type is a value of T -// and is spelled as one; any other one-field variant literal is the option's present arm and is -// unwrapped to its payload. Control: gunbc.instruments.native_emission_controls optional_data_row_cases -// -- the present and absent rows, and a row whose literal's parent is the declared inner type (a wrong -// inner-type comparison would unwrap it and fail at run time). A coproduct merely NAMED Optional +// Within an optional row, a variant literal whose parent IS the declared inner type is a bare T under +// T?: an implicit lift no declared coercion admits (the same class the T?==T and declared-return walls +// refuse), so it REFUSES rather than being spelled -- the typed-expression path for the same row emits +// it bare against Option<..> and rustc refuses it (E0308), so spelling it here would make two +// realizations of one row disagree. Any other one-field variant literal is the option's present arm +// and is unwrapped to its payload. Control: gunbc.instruments.native_emission_controls optional_data_row_cases +// -- the present and absent rows. A coproduct merely NAMED Optional // cannot be emitted at all today (type rendering decides host-option by leaf name); that case is -// lane 2K's RED, not covered here. The more-than-one-field refusal emits a compile_error! and has no -// run-time case. +// lane 2K's RED, not covered here. The two refusal arms (a bare inner-type literal, a present literal +// with more than one field) emit a compile_error! and have no run-time case. fn emit_declared_optional_row_json(value: Node, inner_type_name: String, source_indices: Map, variant_wire: Map) -> EmitterOutcome { match value.expr_data { ExprLiteral { value: LitNull } => Emitted { json: "null" } @@ -514,7 +516,7 @@ fn emit_declared_optional_row_json(value: Node, inner_type_name: String, source_ match pe { Present { value: parent } => if qualified_last_segment(name: parent) == qualified_last_segment(name: inner_type_name) { - emit_data_value_json(value: value, source_indices: source_indices, variant_wire: variant_wire) + Refused { reason: concat("a data row declared ", inner_type_name, "? is initialized with a bare ", inner_type_name, " literal: no declared coercion lifts T into T? (DESIGN 4, 2026-09-26), so spell it Present { value: .. } or none") } } else { match value.children |> first { Absent => Emitted { json: "null" } From e033c9b0bb7201ae9e856ab92d8f3cc7945dcf2d Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 18:52:15 +0000 Subject: [PATCH 42/69] G: regenerated v1_compiler_emit.rs for the bare-inner-type refusal (fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index ef6d61be01d..d9526cbd54b 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -1047,11 +1047,9 @@ pub fn emit_declared_optional_row_json( if (crate::v1_std_core::qualified_last_segment(parent.clone()) == crate::v1_std_core::qualified_last_segment(inner_type_name.clone())) { - emit_data_value_json( - value.clone(), - source_indices.clone(), - variant_wire.clone(), - ) + Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("a data row declared ".to_string(), inner_type_name.clone()), "? is initialized with a bare ".to_string()), inner_type_name.clone()), " literal: no declared coercion lifts T into T? (DESIGN 4, 2026-09-26), so spell it Present { value: .. } or none".to_string()), +}) } else { match value.children.clone().first().cloned() { std::option::Option::None => Rc::new(EmitterOutcome::Emitted { From ca9bfc54d528491db8afa244002a4a52a66d2fb3 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 19:26:36 +0000 Subject: [PATCH 43/69] G: restore optional_data_row_cases' closing bracket lost in the merge resolution Co-Authored-By: Claude Opus 5.5 (1M context) --- dag/gunbc/instruments/native_emission_controls.dag | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index 4e25e8e3af5..31aa5de4900 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -275,6 +275,8 @@ fn optional_data_row_cases() -> List { identity: "optional_data_row_red_absent_answers_absent", held: control_optional_brand_value(d: control_optional_brand_absent) == "" } + ] +} // RULE: a list index is realized as the optional its type says it is. v1.compiler.infer_access // check_index_access_node types `xs[i]` as `T?`, an out-of-range index having no element, and the From 9c914ec1ab0575763a5569ab4c8c9133f05ed68a Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 19:36:39 +0000 Subject: [PATCH 44/69] C4: bootstrap v1_std_core.rs = main's copy plus C4's EqualityOptionalityMismatch arms (regenerated next) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_std_core.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/v1/stage0/src/v1_std_core.rs b/src/v1/stage0/src/v1_std_core.rs index 5c05b25fcc5..505afb16f40 100644 --- a/src/v1/stage0/src/v1_std_core.rs +++ b/src/v1/stage0/src/v1_std_core.rs @@ -871,6 +871,10 @@ pub enum CompilerDiagnostic { member: String, span: Rc, }, + EqualityOptionalityMismatch { + optional_side: String, + span: Rc, + }, TypeArgumentArityMismatch { type_name: String, supplied: i64, @@ -1067,6 +1071,7 @@ pub fn diagnostic_to_span(d: Rc) -> Rc { CompilerDiagnostic::CallNamedArgOnFunctionValue { span: s, .. } => s.clone(), CompilerDiagnostic::EqualityOnFunctionMember { span: s, .. } => s.clone(), CompilerDiagnostic::EqualityMemberUnjudgeable { span: s, .. } => s.clone(), + CompilerDiagnostic::EqualityOptionalityMismatch { span: s, .. } => s.clone(), CompilerDiagnostic::TypeArgumentArityMismatch { span: s, .. } => s.clone(), CompilerDiagnostic::TypeArgumentKindMismatch { span: s, .. } => s.clone(), CompilerDiagnostic::TypeParameterInValuePosition { span: s, .. } => s.clone(), @@ -1146,6 +1151,7 @@ pub fn diagnostic_to_message(d: Rc) -> String { CompilerDiagnostic::CallNamedArgOnFunctionValue { callee: c, argument: a, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("call shape mismatch calling function value '".to_string(), c.clone()), "': named argument '".to_string()), a.clone()), "' is not supported — use positional arguments".to_string()), CompilerDiagnostic::EqualityOnFunctionMember { type_name: t, member: m, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("equality is not defined for '".to_string(), t.clone()), "': member '".to_string()), m.clone()), "' is function-valued, and function equality has no denotation — compare a declared identity for this type instead of '=='".to_string()), CompilerDiagnostic::EqualityMemberUnjudgeable { type_name: t, member: m, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("equality admission for '".to_string(), t.clone()), "' cannot be judged: ".to_string()), m.clone()), " — '==' is refused rather than admitted on an unjudged member".to_string()), + CompilerDiagnostic::EqualityOptionalityMismatch { optional_side: side, .. } => v1_rt::concat(v1_rt::concat("'==' compares an optional value with a required one (the ".to_string(), side.clone()), " operand is optional): no declared coercion lifts T into T?, so the comparison has no single meaning -- compare against Present { value: .. } or match on the optional".to_string()), CompilerDiagnostic::TypeArgumentArityMismatch { type_name: t, supplied: s, declared: d, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("type argument arity mismatch applying '".to_string(), t.clone()), "': ".to_string()), (s.clone()).to_string()), " type argument(s) supplied, ".to_string()), (d.clone()).to_string()), " type parameter(s) declared".to_string()), CompilerDiagnostic::TypeArgumentKindMismatch { type_name: t, param_name: p, kind_name: k, supplied: sup, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("type argument does not inhabit the declared kind applying '".to_string(), t.clone()), "': parameter '".to_string()), p.clone()), "' is declared '".to_string()), k.clone()), "', and '".to_string()), sup.clone()), "' is not one of its inhabitants".to_string()), CompilerDiagnostic::TypeParameterInValuePosition { name: n, .. } => v1_rt::concat(v1_rt::concat("'".to_string(), n.clone()), "' is a type parameter, not a value: a name bound as a type may not stand in an expression position".to_string()), @@ -1451,6 +1457,10 @@ pub fn diagnostic_disposition(d: Rc) -> Rc Rc::new(DiagnosticDisposition { severity: DiagnosticSeverity::SeverityError, gate: Rc::new(DiagnosticGateDisposition::GateBlocking), +}), + CompilerDiagnostic::EqualityOptionalityMismatch { .. } => Rc::new(DiagnosticDisposition { + severity: DiagnosticSeverity::SeverityError, + gate: Rc::new(DiagnosticGateDisposition::GateBlocking), }), CompilerDiagnostic::TypeArgumentArityMismatch { .. } => Rc::new(DiagnosticDisposition { severity: DiagnosticSeverity::SeverityError, From f39b718408261f3bd74e85a8ba28b4bf3a68fd1f Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 19:50:11 +0000 Subject: [PATCH 45/69] G: pin the bare-lift refusal with an enrolled expected-refusal witness (side-chat blocker) Emitted-Rust claim over a T? row whose T has a nested-record variant, so the row reaches the JSON serializer. The red requires the refusal reason and no serde realization; the Present-spelled control requires serde and no refusal. The flat-variant specimen takes the typed-expression path and would not pin the arm. Co-Authored-By: Claude Opus 5.5 (1M context) --- ...ata_row_bare_lift_refusal_witness_test.dag | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag diff --git a/dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag b/dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag new file mode 100644 index 00000000000..95d17fe4fbb --- /dev/null +++ b/dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag @@ -0,0 +1,40 @@ +module test.claim.optional_data_row_bare_lift_refusal_witness + +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } +import std.types { Bool, String } + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +// THE BARE-LIFT REFUSAL IN v1.compiler.emit emit_declared_optional_row_json, PINNED (side-chat review +// of gunbc#13202). A data row declared `T?` whose initializer is a bare variant of T itself is an +// implicit T -> T? lift no declared coercion admits; the serializer refuses it with a located reason +// rather than spelling it. The row's T is a coproduct with a NESTED-RECORD variant on purpose: that is +// what routes the row through the JSON serializer (v1.compiler.emit_rust emit_data_def_body, +// has_nested_records_node). A flat variant goes down the typed-expression path instead, which is the +// specimen that exposed this and does not reach the arm at all -- so a witness built on it would stay +// green with the arm reverted. +// +// The red requires the refusal reason in the emitted module and NO serde realization of the row. The +// control is the same row spelled Present { value: .. }: it must be realized by serde and must not +// carry the refusal. Reverting the Refused arm makes the red emit a serde parse of the row and fail. +data bare_inner_variant_row_source: String = "module optional_bare_lift\n\ntype Inner {\n n: Int\n}\n\ntype Shape\n = Circle { inner: Inner }\n | NoShape\n\ndata shape_row: Shape? = Circle { inner: Inner { n: 1 } }\n" + +data present_spelled_row_source: String = "module optional_present_spelled\n\ntype Inner {\n n: Int\n}\n\ntype Shape\n = Circle { inner: Inner }\n | NoShape\n\ndata shape_row: Shape? = Present { value: Circle { inner: Inner { n: 1 } } }\n" + +test fn bare_inner_variant_under_optional_row_refuses() -> Bool { + compile_dag_rust_emit_check( + bare_inner_variant_row_source, + "src/optional_bare_lift.rs", + ["no declared coercion lifts T into T?"], + ["serde_json::from_str("] + ) +} + +test fn present_spelled_optional_row_is_realized() -> Bool { + compile_dag_rust_emit_check( + present_spelled_row_source, + "src/optional_present_spelled.rs", + ["serde_json::from_str("], + ["no declared coercion lifts T into T?"] + ) +} From ab6793af1d759812a1f3ad9e96f8d1067301e4ac Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 20:15:47 +0000 Subject: [PATCH 46/69] C4: regenerate infer mirror over main with #13196 (fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 73 ++++++++++++++++++++------ 1 file changed, 57 insertions(+), 16 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 21fbd9fd2aa..2dbb3f44b0a 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -285,8 +285,8 @@ use crate::v1_std_core::CompilerDiagnostic::{ AlgebraApplicationEvidenceUnavailable, AmbiguousReference, BareNoneNotAdmittedByFieldType, CallArgumentDuplicate, CallArgumentNameUnknown, CallNamedArgOnFunctionValue, CallPositionalDeficit, CallPositionalSurplus, ConstructorCallAdmissionRefused, - EqualityMemberUnjudgeable, EqualityOnFunctionMember, FieldNotFound, - FrontierOccurrenceBudgetExceeded, InternalError, KernelMintShapeMismatch, + EqualityMemberUnjudgeable, EqualityOnFunctionMember, EqualityOptionalityMismatch, + FieldNotFound, FrontierOccurrenceBudgetExceeded, InternalError, KernelMintShapeMismatch, MethodExistenceFrontierAdmitted, MethodExistenceUndecided, MethodNotFound, MissingField, OptionalCastNotEliminated, ReceiverTypeUnestablished, ServiceConfigReferenceJudgmentDeferred, SiblingOperandEffectOrderUndetermined, SoleConstructorViolation, @@ -5125,6 +5125,22 @@ pub fn equality_operand_is_presence_literal( } } +pub fn equality_operand_is_optional( + n: Rc, + source_indices: Rc>>, +) -> bool { + match n.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: rt, .. }) => { + ((rt.return_cardinality.clone() == Cardinality::CardOptional) + || ((crate::v1_std_core::qualified_last_segment( + crate::v1_std_core::authored_name_at(source_indices.clone(), rt.clone()), + ) == "Optional".to_string()) + && ((rt.children.clone().len() as i64) == 1))) + } + _ => false, + } +} + pub fn equality_admission_refusal_diag( r: Rc, span: Rc, @@ -5200,18 +5216,32 @@ pub fn equality_admission_diags( { Rc::new(vec![]) } else { - match equality_operand_admission( - lt.clone(), - scope.clone(), - v1_rt::rc_empty_map::(), - 0, - ) { - Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( - equality_admission_refusal_diag(r.clone(), span.clone()), - scope.module_name.clone(), - )]), - std::option::Option::None => match equality_operand_admission( - rt.clone(), + if (equality_operand_is_optional(left_typed.clone(), source_indices.clone()) + != equality_operand_is_optional( + right_typed.clone(), + source_indices.clone(), + )) + { + { + let side = if equality_operand_is_optional( + left_typed.clone(), + source_indices.clone(), + ) { + "left".to_string() + } else { + "right".to_string() + }; + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::EqualityOptionalityMismatch { + optional_side: side.clone(), + span: span.clone(), + }), + scope.module_name.clone(), + )]) + } + } else { + match equality_operand_admission( + lt.clone(), scope.clone(), v1_rt::rc_empty_map::(), 0, @@ -5220,8 +5250,19 @@ pub fn equality_admission_diags( equality_admission_refusal_diag(r.clone(), span.clone()), scope.module_name.clone(), )]), - std::option::Option::None => Rc::new(vec![]), - }, + std::option::Option::None => match equality_operand_admission( + rt.clone(), + scope.clone(), + v1_rt::rc_empty_map::(), + 0, + ) { + Some(r) => Rc::new(vec![crate::v1_std_core::make_error_node( + equality_admission_refusal_diag(r.clone(), span.clone()), + scope.module_name.clone(), + )]), + std::option::Option::None => Rc::new(vec![]), + }, + } } } } From 27fc5baca4a4022e711937a2901d8f67ef35f7ed Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 20:39:17 +0000 Subject: [PATCH 47/69] C5: regenerate infer mirror over C4 + main with #13196 (fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 89 +++++++++++++++++++++----- 1 file changed, 72 insertions(+), 17 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 2dbb3f44b0a..6f28bca5af0 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -6255,6 +6255,68 @@ pub fn declared_type_inhabitance( } } +pub fn declared_type_carries_optional(declared: Rc, scope: Rc) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( + declared.clone(), + scope.type_env.clone(), + scope.module_name.clone(), + ); + ((((declared.return_cardinality.clone() == Cardinality::CardOptional) + || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared.clone(), + )) == "Optional".to_string())) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared_peeled.clone(), + )) == "Optional".to_string())) + } +} + +pub fn position_is_declared_return(position: DeclaredTypePosition) -> bool { + match position.clone() { + DeclaredTypePosition::PositionDeclaredReturn => true, + _ => false, + } +} + +pub fn required_produced_at_optional_declared( + declared: Rc, + produced: Rc, + scope: Rc, +) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), declared.clone()); + let produced_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), produced.clone()); + let produced_carries_optional = ((produced.return_cardinality.clone() + == Cardinality::CardOptional) + || (crate::v1_std_core::qualified_last_segment(produced_name.clone()) + == "Optional".to_string())); + let produced_is_generic = ((((produced.params.clone().len() as i64) > 0) + || ((produced.inferred.clone() != std::option::Option::None) + && crate::v1_std_core::is_compiler_error( + produced.inferred.clone().clone().unwrap(), + ))) + || match produced.inferred.clone().as_deref().cloned() { + Some(InferredNode::TypeVariable { id: _, .. }) => true, + _ => false, + }); + ((((((declared_type_carries_optional(declared.clone(), scope.clone()) + && !produced_carries_optional.clone()) + && !produced_is_generic.clone()) + && (produced_name.clone() != "".to_string())) + && (declared_name.clone() != "".to_string())) + && !type_node_is_callable(declared.clone())) + && !type_node_is_callable(produced.clone())) + } +} + pub fn optional_produced_at_required_declared( declared: Rc, produced: Rc, @@ -6275,21 +6337,8 @@ pub fn optional_produced_at_required_declared( Some(InferredNode::TypeVariable { id: _, .. }) => true, _ => false, }); - let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( - declared.clone(), - scope.type_env.clone(), - scope.module_name.clone(), - ); - let declared_carries_optional = ((((declared.return_cardinality.clone() - == Cardinality::CardOptional) - || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) - || (crate::v1_std_core::qualified_last_segment(declared_name.clone()) - == "Optional".to_string())) - || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( - source_indices.clone(), - declared_peeled.clone(), - )) == "Optional".to_string())); - ((((((produced_carries_optional.clone() && !declared_carries_optional.clone()) + ((((((produced_carries_optional.clone() + && !declared_type_carries_optional(declared.clone(), scope.clone())) && !declared_is_generic.clone()) && (declared_name.clone() != "".to_string())) && !type_node_is_callable(declared.clone())) @@ -6302,11 +6351,17 @@ pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, ) -> Rc>> { - if optional_produced_at_required_declared( + if (optional_produced_at_required_declared( obligation.declared.clone(), obligation.produced.clone(), scope.clone(), - ) { + ) || (position_is_declared_return(obligation.position.clone()) + && required_produced_at_optional_declared( + obligation.declared.clone(), + obligation.produced.clone(), + scope.clone(), + ))) + { Rc::new(vec![crate::v1_std_core::make_error_node( Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { position: declared_type_position_label( From 0519df020fabba698efcf6a2374e52acaa2aa615 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 22:29:27 +0000 Subject: [PATCH 48/69] C5: refuse a bare T data initializer under a declared T? (ruling A on #13202) Co-Authored-By: Claude Opus 5.5 (1M context) --- ...self_host_equality_admission_witness_test.dag | 16 ++++++++++++++++ src/v1/04_infer.dag | 9 ++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index adbf7beb87e..e43a7929218 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -165,3 +165,19 @@ data return_lift_match_arm_red_source: String = "module ret_probe_arm\nfn g(s: S test fn required_arm_at_optional_return_refuses_blocking() -> Bool { eq_blocking_count(source: return_lift_match_arm_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 } + +// THE SAME CLASS AT A DATA INITIALIZER (ruling A on gunbc#13202). A `data r: T? = ` row was +// emitted bare against Option<..> and refused only downstream by rustc; the checker now refuses it. +// The red's T is a coproduct with a nested-record variant, the specimen that exposed the class; the +// control is the same row spelled Present { value: .. }. +data data_row_bare_lift_red_source: String = "module data_probe_lift\ntype Inner {\n n: Int\n}\ntype Shape\n = Circle { inner: Inner }\n | NoShape\ndata shape_row: Shape? = Circle { inner: Inner { n: 1 } }\n" + +data data_row_present_spelled_green_source: String = "module data_probe_present\ntype Inner {\n n: Int\n}\ntype Shape\n = Circle { inner: Inner }\n | NoShape\ndata shape_row: Shape? = Present { value: Circle { inner: Inner { n: 1 } } }\n" + +test fn bare_data_initializer_at_optional_row_refuses_blocking() -> Bool { + eq_blocking_count(source: data_row_bare_lift_red_source, wanted: "DeclaredTypeNotInhabited") == 1 +} + +test fn present_spelled_data_initializer_stays_admitted() -> Bool { + eq_admitted(source: data_row_present_spelled_green_source) +} diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 408318bd64e..2762eda1be5 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4408,12 +4408,15 @@ fn declared_type_carries_optional(declared: Node, scope: InferScope) -> Bool { // class C5). A fn declared `-> T?` whose body produces a bare T was accepted: no declared coercion // lifts T into T? (DESIGN 4, 2026-09-26), and the Rust emission refused it as E0308 `expected // Option, found T` (gunbc.running_release_identity running_release_member_string). It is judged -// here at the declared return only, the position the ruling names; a bare T bound to a T? PARAMETER -// or field is a different position whose population was not measured by this change and is not -// claimed. The none / Absent presence spellings produce an optional and never reach this arm. +// at the declared return and, by gentle-dove-36 ruling A on gunbc#13202, at a DATA INITIALIZER: a +// `data r: T? = ` row was emitted bare against Option<..> on the typed-expression path and +// refused only downstream by rustc (E0308), which DESIGN 5 does not count as a typed refusal. A bare +// T bound to a T? PARAMETER or record field is a different position whose population was not +// measured by this change and is not claimed. The none / Absent presence spellings produce an optional and never reach this arm. fn position_is_declared_return(position: DeclaredTypePosition) -> Bool { match position { PositionDeclaredReturn => true + PositionDataInitializer => true _ => false } } From a6852b61eb64889dc2ab3d3e86daef0fe68e129c Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 22:29:51 +0000 Subject: [PATCH 49/69] G (ruling A): the bare-lift arm is the exhaustive refusal, unreachable behind C5's data-initializer wall Withdraws the emitted-Rust witness: no T? row with a bare inner-T literal reaches this serializer (both bare and Present-spelled rows take the typed-expression path), so it could not red on revert. The wall is C5's checker refusal at PositionDataInitializer (#13280). Co-Authored-By: Claude Opus 5.5 (1M context) --- ...ata_row_bare_lift_refusal_witness_test.dag | 40 ------------------- src/v1/05_emit.dag | 15 +++---- 2 files changed, 8 insertions(+), 47 deletions(-) delete mode 100644 dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag diff --git a/dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag b/dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag deleted file mode 100644 index 95d17fe4fbb..00000000000 --- a/dag/test/claim/optional_data_row_bare_lift_refusal_witness_test.dag +++ /dev/null @@ -1,40 +0,0 @@ -module test.claim.optional_data_row_bare_lift_refusal_witness - -import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } -import std.types { Bool, String } - -data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly - -// THE BARE-LIFT REFUSAL IN v1.compiler.emit emit_declared_optional_row_json, PINNED (side-chat review -// of gunbc#13202). A data row declared `T?` whose initializer is a bare variant of T itself is an -// implicit T -> T? lift no declared coercion admits; the serializer refuses it with a located reason -// rather than spelling it. The row's T is a coproduct with a NESTED-RECORD variant on purpose: that is -// what routes the row through the JSON serializer (v1.compiler.emit_rust emit_data_def_body, -// has_nested_records_node). A flat variant goes down the typed-expression path instead, which is the -// specimen that exposed this and does not reach the arm at all -- so a witness built on it would stay -// green with the arm reverted. -// -// The red requires the refusal reason in the emitted module and NO serde realization of the row. The -// control is the same row spelled Present { value: .. }: it must be realized by serde and must not -// carry the refusal. Reverting the Refused arm makes the red emit a serde parse of the row and fail. -data bare_inner_variant_row_source: String = "module optional_bare_lift\n\ntype Inner {\n n: Int\n}\n\ntype Shape\n = Circle { inner: Inner }\n | NoShape\n\ndata shape_row: Shape? = Circle { inner: Inner { n: 1 } }\n" - -data present_spelled_row_source: String = "module optional_present_spelled\n\ntype Inner {\n n: Int\n}\n\ntype Shape\n = Circle { inner: Inner }\n | NoShape\n\ndata shape_row: Shape? = Present { value: Circle { inner: Inner { n: 1 } } }\n" - -test fn bare_inner_variant_under_optional_row_refuses() -> Bool { - compile_dag_rust_emit_check( - bare_inner_variant_row_source, - "src/optional_bare_lift.rs", - ["no declared coercion lifts T into T?"], - ["serde_json::from_str("] - ) -} - -test fn present_spelled_optional_row_is_realized() -> Bool { - compile_dag_rust_emit_check( - present_spelled_row_source, - "src/optional_present_spelled.rs", - ["serde_json::from_str("], - ["no declared coercion lifts T into T?"] - ) -} diff --git a/src/v1/05_emit.dag b/src/v1/05_emit.dag index 0cc367a52bd..7c1f9fc28c7 100644 --- a/src/v1/05_emit.dag +++ b/src/v1/05_emit.dag @@ -500,15 +500,16 @@ fn emit_data_fields_json(value: Node, source_indices: Map, // to be NAMED Optional keeps its own wire policy (review on gunbc#13202: a leaf-name test here was a // second, unrostered authority that would have serialized such a coproduct as null or a bare payload). // Within an optional row, a variant literal whose parent IS the declared inner type is a bare T under -// T?: an implicit lift no declared coercion admits (the same class the T?==T and declared-return walls -// refuse), so it REFUSES rather than being spelled -- the typed-expression path for the same row emits -// it bare against Option<..> and rustc refuses it (E0308), so spelling it here would make two -// realizations of one row disagree. Any other one-field variant literal is the option's present arm -// and is unwrapped to its payload. Control: gunbc.instruments.native_emission_controls optional_data_row_cases +// T?: an implicit lift no declared coercion admits. That arm REFUSES, and it is the refusal exhaustive +// matching requires -- NOT coverage. It is unreachable: v1.compiler.infer refuses a bare T data +// initializer under a declared T? (the C5 wall, optional_at_required_obligation_diags at +// PositionDataInitializer), and an accepted row of that shape takes the typed-expression path, never +// this serializer (measured on gunbc#13202). Any other one-field variant literal is the option's +// present arm and is unwrapped to its payload. Control: gunbc.instruments.native_emission_controls optional_data_row_cases // -- the present and absent rows. A coproduct merely NAMED Optional // cannot be emitted at all today (type rendering decides host-option by leaf name); that case is -// lane 2K's RED, not covered here. The two refusal arms (a bare inner-type literal, a present literal -// with more than one field) emit a compile_error! and have no run-time case. +// lane 2K's RED, not covered here. Neither refusal arm (a bare inner-type literal, a present literal +// with more than one field) is coverage of anything; both exist only so the match is exhaustive. fn emit_declared_optional_row_json(value: Node, inner_type_name: String, source_indices: Map, variant_wire: Map) -> EmitterOutcome { match value.expr_data { ExprLiteral { value: LitNull } => Emitted { json: "null" } From e862920f0c15979331971f1424fb866126ef1e3d Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 5 Oct 2026 23:02:17 +0000 Subject: [PATCH 50/69] C5: regenerated infer mirror for the data-initializer wall (fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 6f28bca5af0..8f5e6e9ec0b 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -6279,6 +6279,7 @@ pub fn declared_type_carries_optional(declared: Rc, scope: Rc) pub fn position_is_declared_return(position: DeclaredTypePosition) -> bool { match position.clone() { DeclaredTypePosition::PositionDeclaredReturn => true, + DeclaredTypePosition::PositionDataInitializer => true, _ => false, } } From c9b71b0ed2d74fd3cac27772014c24b6f85d80a3 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 00:59:24 +0000 Subject: [PATCH 51/69] C5 (review 76818): position_is_declared_return -> position_forbids_bare_lift It answers true at the declared return AND the data initializer; the name now says the fact it decides (DESIGN 3, one name per meaning). Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/04_infer.dag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 2762eda1be5..9d6e1a392aa 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4413,7 +4413,7 @@ fn declared_type_carries_optional(declared: Node, scope: InferScope) -> Bool { // refused only downstream by rustc (E0308), which DESIGN 5 does not count as a typed refusal. A bare // T bound to a T? PARAMETER or record field is a different position whose population was not // measured by this change and is not claimed. The none / Absent presence spellings produce an optional and never reach this arm. -fn position_is_declared_return(position: DeclaredTypePosition) -> Bool { +fn position_forbids_bare_lift(position: DeclaredTypePosition) -> Bool { match position { PositionDeclaredReturn => true PositionDataInitializer => true @@ -4477,7 +4477,7 @@ fn optional_produced_at_required_declared(declared: Node, produced: Node, scope: // fn optional_at_required_obligation_diags(obligation: DeclaredTypeObligation, scope: InferScope) -> List { if optional_produced_at_required_declared(declared: obligation.declared, produced: obligation.produced, scope: scope) - || (position_is_declared_return(position: obligation.position) && required_produced_at_optional_declared(declared: obligation.declared, produced: obligation.produced, scope: scope)) { + || (position_forbids_bare_lift(position: obligation.position) && required_produced_at_optional_declared(declared: obligation.declared, produced: obligation.produced, scope: scope)) { [make_error_node( diagnostic: DeclaredTypeNotInhabited { position: declared_type_position_label(position: obligation.position, subject: obligation.subject), From 51ff80017d03e4e93e5d013dc1fefbc856392ca0 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 01:25:12 +0000 Subject: [PATCH 52/69] C5: regenerated infer mirror for the rename (fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_infer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 8f5e6e9ec0b..efa29552bec 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -6276,7 +6276,7 @@ pub fn declared_type_carries_optional(declared: Rc, scope: Rc) } } -pub fn position_is_declared_return(position: DeclaredTypePosition) -> bool { +pub fn position_forbids_bare_lift(position: DeclaredTypePosition) -> bool { match position.clone() { DeclaredTypePosition::PositionDeclaredReturn => true, DeclaredTypePosition::PositionDataInitializer => true, @@ -6356,7 +6356,7 @@ pub fn optional_at_required_obligation_diags( obligation.declared.clone(), obligation.produced.clone(), scope.clone(), - ) || (position_is_declared_return(obligation.position.clone()) + ) || (position_forbids_bare_lift(obligation.position.clone()) && required_produced_at_optional_declared( obligation.declared.clone(), obligation.produced.clone(), From f5b1edbb24857f3a818de9757d2a347c9718d102 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 05:34:29 +0000 Subject: [PATCH 53/69] C5 (review 76904): refuse a match that mixes a bare arm and an optional arm, either order Co-Authored-By: Claude Sonnet 5.5 --- ...f_host_equality_admission_witness_test.dag | 8 +++++ src/v1/04_infer.dag | 36 +++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index e43a7929218..a70da56d288 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -166,6 +166,14 @@ test fn required_arm_at_optional_return_refuses_blocking() -> Bool { eq_blocking_count(source: return_lift_match_arm_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 } +// Arm ORDER must not decide the verdict (review 76904): the join keeps the first arm's type, so with +// `none` listed first the bare arm was never judged against the declared return. +data return_lift_match_arm_swapped_red_source: String = "module ret_probe_arm_swapped\nfn g(s: String) -> String? {\n match s {\n \"b\" => none\n _ => s\n }\n}\n" + +test fn required_arm_after_none_arm_refuses_blocking() -> Bool { + eq_blocking_count(source: return_lift_match_arm_swapped_red_source, wanted: "InternalError") >= 1 +} + // THE SAME CLASS AT A DATA INITIALIZER (ruling A on gunbc#13202). A `data r: T? = ` row was // emitted bare against Option<..> and refused only downstream by rustc; the checker now refuses it. // The red's T is a coproduct with a nested-record variant, the specimen that exposed the class; the diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 9d6e1a392aa..5e457756acb 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -3020,9 +3020,45 @@ fn match_arm_types_are_proven_disjoint(unified_arm_type: Node, arm_type: Node, s } } +// A match arm that is a bare concrete T beside an arm that is T? (or `none`) is the implicit T -> T? +// lift the declared-return wall refuses, reached through the join instead: the join keeps ONE arm's +// type, so which arm was listed first decided whether the declared-return seam ever saw the bare T. +// `if` already refuses the same mix through node_type_compatible; a match is judged the same way. +fn match_arm_type_is_optional(t: Node, scope: InferScope) -> Bool { + t.return_cardinality == CardOptional + || qualified_last_segment(name: authored_name_at(source_indices: scope.type_env.source_indices, node: t)) == "Optional" +} + +fn match_arm_type_is_bare_concrete(t: Node, scope: InferScope) -> Bool { + let name = authored_name_at(source_indices: scope.type_env.source_indices, node: t) + let generic = (t.params |> count) > 0 + || (t.inferred != none && is_compiler_error(inferred: t.inferred.value)) + || match t.inferred { + Present { value: TypeVariable { id: _ } } => true + _ => false + } + name != "" && !generic && !match_arm_type_is_optional(t: t, scope: scope) +} + +fn match_arm_mixes_bare_and_optional(unified_arm_type: Node, arm_type: Node, scope: InferScope) -> Bool { + (match_arm_type_is_optional(t: unified_arm_type, scope: scope) && match_arm_type_is_bare_concrete(t: arm_type, scope: scope)) + || (match_arm_type_is_bare_concrete(t: unified_arm_type, scope: scope) && match_arm_type_is_optional(t: arm_type, scope: scope)) +} + fn match_arm_join_diagnostics(unified_arm_type: Node, arm: ArmInferResult, scope: InferScope) -> List { if arm_body_diverges(body: arm_body(n: arm.typed_arm)) { [] + } else if match_arm_mixes_bare_and_optional(unified_arm_type: unified_arm_type, arm_type: arm.body_type, scope: scope) { + [inference_error( + message: concat( + "match arms mix a required and an optional type: ", + node_type_shape(n: unified_arm_type, source_indices: scope.type_env.source_indices), + " vs ", + node_type_shape(n: arm.body_type, source_indices: scope.type_env.source_indices) + ), + span: arm_body(n: arm.typed_arm).span, + module_name: scope.module_name + )] } else if match_arm_types_are_proven_disjoint( unified_arm_type: unified_arm_type, arm_type: arm.body_type, From 9580f9d6ae2a230ecc1fa22c486e5f50c08be6da Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 05:59:40 +0000 Subject: [PATCH 54/69] C5: regenerated infer mirror for the match-arm wall (fixed point) Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_infer.rs | 72 ++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index efa29552bec..3fa21c6de41 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -4208,6 +4208,43 @@ pub fn match_arm_types_are_proven_disjoint( } } +pub fn match_arm_type_is_optional(t: Rc, scope: Rc) -> bool { + ((t.return_cardinality.clone() == Cardinality::CardOptional) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + t.clone(), + )) == "Optional".to_string())) +} + +pub fn match_arm_type_is_bare_concrete(t: Rc, scope: Rc) -> bool { + { + let name = crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + t.clone(), + ); + let generic = ((((t.params.clone().len() as i64) > 0) + || ((t.inferred.clone() != std::option::Option::None) + && crate::v1_std_core::is_compiler_error(t.inferred.clone().clone().unwrap()))) + || match t.inferred.clone().as_deref().cloned() { + Some(InferredNode::TypeVariable { id: _, .. }) => true, + _ => false, + }); + (((name.clone() != "".to_string()) && !generic.clone()) + && !match_arm_type_is_optional(t.clone(), scope.clone())) + } +} + +pub fn match_arm_mixes_bare_and_optional( + unified_arm_type: Rc, + arm_type: Rc, + scope: Rc, +) -> bool { + ((match_arm_type_is_optional(unified_arm_type.clone(), scope.clone()) + && match_arm_type_is_bare_concrete(arm_type.clone(), scope.clone())) + || (match_arm_type_is_bare_concrete(unified_arm_type.clone(), scope.clone()) + && match_arm_type_is_optional(arm_type.clone(), scope.clone()))) +} + pub fn match_arm_join_diagnostics( unified_arm_type: Rc, arm: Rc, @@ -4216,7 +4253,7 @@ pub fn match_arm_join_diagnostics( if arm_body_diverges(crate::v1_std_core::arm_body(arm.typed_arm.clone())) { Rc::new(vec![]) } else { - if match_arm_types_are_proven_disjoint( + if match_arm_mixes_bare_and_optional( unified_arm_type.clone(), arm.body_type.clone(), scope.clone(), @@ -4225,7 +4262,7 @@ pub fn match_arm_join_diagnostics( v1_rt::concat( v1_rt::concat( v1_rt::concat( - "match arms produce proven-disjoint types: ".to_string(), + "match arms mix a required and an optional type: ".to_string(), crate::v1_compiler_infer_types::node_type_shape( unified_arm_type.clone(), scope.type_env.clone().source_indices.clone(), @@ -4244,7 +4281,36 @@ pub fn match_arm_join_diagnostics( scope.module_name.clone(), )]) } else { - Rc::new(vec![]) + if match_arm_types_are_proven_disjoint( + unified_arm_type.clone(), + arm.body_type.clone(), + scope.clone(), + ) { + Rc::new(vec![inference_error( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + "match arms produce proven-disjoint types: ".to_string(), + crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + ), + " vs ".to_string(), + ), + crate::v1_compiler_infer_types::node_type_shape( + arm.body_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + ), + crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), + scope.module_name.clone(), + )]) + } else { + Rc::new(vec![]) + } } } } From acdceafe8fc576999ffcc28e50599292afe86381 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 06:09:57 +0000 Subject: [PATCH 55/69] C5 (review, 9580f9d6ae): typed DeclaredTypeNotInhabited at the arm; optionality via declared_type_carries_optional Co-Authored-By: Claude Sonnet 5.5 --- ...f_host_equality_admission_witness_test.dag | 2 +- src/v1/04_infer.dag | 29 +++++++++---------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index a70da56d288..164bed32a04 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -171,7 +171,7 @@ test fn required_arm_at_optional_return_refuses_blocking() -> Bool { data return_lift_match_arm_swapped_red_source: String = "module ret_probe_arm_swapped\nfn g(s: String) -> String? {\n match s {\n \"b\" => none\n _ => s\n }\n}\n" test fn required_arm_after_none_arm_refuses_blocking() -> Bool { - eq_blocking_count(source: return_lift_match_arm_swapped_red_source, wanted: "InternalError") >= 1 + eq_blocking_count(source: return_lift_match_arm_swapped_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 } // THE SAME CLASS AT A DATA INITIALIZER (ruling A on gunbc#13202). A `data r: T? = ` row was diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 5e457756acb..b2a2dd6a7d2 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -3024,11 +3024,9 @@ fn match_arm_types_are_proven_disjoint(unified_arm_type: Node, arm_type: Node, s // lift the declared-return wall refuses, reached through the join instead: the join keeps ONE arm's // type, so which arm was listed first decided whether the declared-return seam ever saw the bare T. // `if` already refuses the same mix through node_type_compatible; a match is judged the same way. -fn match_arm_type_is_optional(t: Node, scope: InferScope) -> Bool { - t.return_cardinality == CardOptional - || qualified_last_segment(name: authored_name_at(source_indices: scope.type_env.source_indices, node: t)) == "Optional" -} - +// Optionality is decided by declared_type_carries_optional, the one authority, so the leaf-name +// identity debt it names (2K) is carried there and not re-spelled here. It is a source type error, +// carried as DeclaredTypeNotInhabited at the offending arm. fn match_arm_type_is_bare_concrete(t: Node, scope: InferScope) -> Bool { let name = authored_name_at(source_indices: scope.type_env.source_indices, node: t) let generic = (t.params |> count) > 0 @@ -3037,26 +3035,25 @@ fn match_arm_type_is_bare_concrete(t: Node, scope: InferScope) -> Bool { Present { value: TypeVariable { id: _ } } => true _ => false } - name != "" && !generic && !match_arm_type_is_optional(t: t, scope: scope) + name != "" && !generic && !declared_type_carries_optional(declared: t, scope: scope) } fn match_arm_mixes_bare_and_optional(unified_arm_type: Node, arm_type: Node, scope: InferScope) -> Bool { - (match_arm_type_is_optional(t: unified_arm_type, scope: scope) && match_arm_type_is_bare_concrete(t: arm_type, scope: scope)) - || (match_arm_type_is_bare_concrete(t: unified_arm_type, scope: scope) && match_arm_type_is_optional(t: arm_type, scope: scope)) + (declared_type_carries_optional(declared: unified_arm_type, scope: scope) && match_arm_type_is_bare_concrete(t: arm_type, scope: scope)) + || (match_arm_type_is_bare_concrete(t: unified_arm_type, scope: scope) && declared_type_carries_optional(declared: arm_type, scope: scope)) } fn match_arm_join_diagnostics(unified_arm_type: Node, arm: ArmInferResult, scope: InferScope) -> List { if arm_body_diverges(body: arm_body(n: arm.typed_arm)) { [] } else if match_arm_mixes_bare_and_optional(unified_arm_type: unified_arm_type, arm_type: arm.body_type, scope: scope) { - [inference_error( - message: concat( - "match arms mix a required and an optional type: ", - node_type_shape(n: unified_arm_type, source_indices: scope.type_env.source_indices), - " vs ", - node_type_shape(n: arm.body_type, source_indices: scope.type_env.source_indices) - ), - span: arm_body(n: arm.typed_arm).span, + [make_error_node( + diagnostic: DeclaredTypeNotInhabited { + position: "match arm", + expected: node_type_shape(n: unified_arm_type, source_indices: scope.type_env.source_indices), + got: node_type_shape(n: arm.body_type, source_indices: scope.type_env.source_indices), + span: arm_body(n: arm.typed_arm).span + }, module_name: scope.module_name )] } else if match_arm_types_are_proven_disjoint( From 44f997fa86120116e9ba8a7ec9a2e1d67e08bc36 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 06:14:20 +0000 Subject: [PATCH 56/69] C5 (review 76923): own failure-mode row for the bare-lift walls; census restates the two-way positions Co-Authored-By: Claude Sonnet 5.5 --- ...ue_admitted_where_optional_is_declared.dag | 26 +++++++++++++++++++ ...f_host_equality_admission_witness_test.dag | 2 +- src/v1/04_infer.dag | 7 +++-- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag diff --git a/dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag b/dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag new file mode 100644 index 00000000000..01f417e8c53 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag @@ -0,0 +1,26 @@ +module gunbc.recurring_failure_mode.bare_value_admitted_where_optional_is_declared + +import std.types { NonEmptyStr } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data bare_value_admitted_where_optional_is_declared: RecurringFailureMode = RecurringFailureMode { + identity: "bare_value_admitted_where_optional_is_declared" as NonEmptyStr, + + receipts: [ + "bare value where an optional is declared: a fn declared `-> T?` whose body produces a bare T, a `data r: T? = ` row, or a match whose arms mix a bare T with an optional (gunbc.running_release_identity running_release_member_string returned the bare member under `-> String?`). No declared coercion route lifts T into T? (DESIGN section 4, operator ruling 2026-09-26), yet the checker accepted each with zero diagnostics. It is the reverse of optional_admitted_where_a_required_value_is_declared, and a different class from optional_compared_with_required_value, which is the binary-operator seam.", + + "HARM: the Rust emission refused the declared-return and data-row forms downstream as rustc E0308 (`expected Option, found T`), which DESIGN section 5 does not count as a typed refusal; the match form was order-dependent, because the join keeps ONE arm's type, so with `none` listed first the bare arm was never judged against the declared return (join_answers_with_one_arm_others_unjudged).", + + "WALL: v1.compiler.infer optional_at_required_obligation_diags refuses a bare concrete T at PositionDeclaredReturn and PositionDataInitializer (position_forbids_bare_lift) as DeclaredTypeNotInhabited, and match_arm_join_diagnostics refuses a match whose arms mix a bare concrete type with an optional in either arm order, as DeclaredTypeNotInhabited located at the offending arm. Optionality is decided by declared_type_carries_optional, which still decides partly by leaf name: that is the bare-name identity debt routed to the identity-keying lane, carried there and not re-spelled.", + + "EVIDENCE: test.claim.self_host_equality_admission_witness. Reds: a bare return, a bare match arm before a none arm, a bare match arm after a none arm, and a bare data initializer, each refused as blocking DeclaredTypeNotInhabited. Controls: an explicit Present return, an absent return, and a Present-spelled data row, all admitted.", + + "RUNG FOUND AT: 1 on the Rust emission path (rustc refusal); the interpretation path accepted silently.", + + "RUNG NOW: 3 at three paths only -- the declared return, the data initializer, and the match-arm join -- each with an enrolled red and positive control. A bare T bound to a T? let annotation, record field, call argument or parameter is a different position whose population this change did not measure, and no rung is claimed there; the class's rung is the minimum across its in-scope paths, so it is not claimed beyond those three.", + + "CEILING: 4 is not attainable while the surface can spell a bare value beside an optional declaration. NEXT-RUNG TRIGGER for the unclaimed positions: measuring the corpus population at let, field, argument and parameter positions and enrolling their reds, which is possible now and unbuilt; and for the leaf-name optionality decision, declaration-decided optionality in the checker.", + ], + + evidence: [], +} diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 164bed32a04..1d1e64984da 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -138,7 +138,7 @@ test fn optional_compared_with_optional_stays_admitted() -> Bool { eq_admitted(source: optionality_both_optional_green_source) } -// C5, THE SAME CLASS AT THE DECLARED RETURN: a fn declared `-> T?` whose body produces a bare T. No +// C5 (gunbc.recurring_failure_mode bare_value_admitted_where_optional_is_declared), AT THE DECLARED RETURN: a fn declared `-> T?` whose body produces a bare T. No // declared coercion lifts T into T?, and the Rust emission refused it (E0308, gunbc.running_release_ // identity running_release_member_string). The red is a bare-Int body under `-> Int?`; the controls // are the explicit present spelling and the absent spelling, which the arm must not widen into. diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index b2a2dd6a7d2..24b33fd1392 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -4021,7 +4021,10 @@ fn foreign_concrete_coproduct_where_parent_required( // // CARDINALITY VERDICT ONLY (optional_at_required_obligation_diags): PositionRecordLiteralField, // PositionDeclaredReturn, PositionLetAnnotation, PositionDataInitializer. Each builds the same -// DeclaredTypeObligation and is refused when an optional stands where a required value is declared; +// DeclaredTypeObligation and is refused when an optional stands where a required value is declared +// (and, at PositionDeclaredReturn and PositionDataInitializer ONLY, when a bare required value stands +// where an optional is declared: position_forbids_bare_lift, the other direction; let and record-field +// stay one-way); // the relation's other arms are NOT consulted there, because those seams already carry their own // older chains (declared_type_conformance_diags, the record-literal field chain) whose agreement // with this relation has not been measured on the corpus. So at these four the honest claim is one @@ -4437,7 +4440,7 @@ fn declared_type_carries_optional(declared: Node, scope: InferScope) -> Bool { || qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: declared_peeled)) == "Optional" } -// THE MIRROR, AT THE DECLARED RETURN (gunbc.recurring_failure_mode optional_compared_with_required_value, +// THE MIRROR, AT THE DECLARED RETURN (gunbc.recurring_failure_mode bare_value_admitted_where_optional_is_declared, // class C5). A fn declared `-> T?` whose body produces a bare T was accepted: no declared coercion // lifts T into T? (DESIGN 4, 2026-09-26), and the Rust emission refused it as E0308 `expected // Option, found T` (gunbc.running_release_identity running_release_member_string). It is judged From 54cb52a87eeef08785a91549e4bf7cb5d4b99684 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 06:35:10 +0000 Subject: [PATCH 57/69] C5: regenerated infer mirror for the typed match-arm diagnostic (fixed point) Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_infer.rs | 41 +++++++++----------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 3fa21c6de41..eaf413fdef6 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -4208,14 +4208,6 @@ pub fn match_arm_types_are_proven_disjoint( } } -pub fn match_arm_type_is_optional(t: Rc, scope: Rc) -> bool { - ((t.return_cardinality.clone() == Cardinality::CardOptional) - || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( - scope.type_env.clone().source_indices.clone(), - t.clone(), - )) == "Optional".to_string())) -} - pub fn match_arm_type_is_bare_concrete(t: Rc, scope: Rc) -> bool { { let name = crate::v1_std_core::authored_name_at( @@ -4230,7 +4222,7 @@ pub fn match_arm_type_is_bare_concrete(t: Rc, scope: Rc) -> bo _ => false, }); (((name.clone() != "".to_string()) && !generic.clone()) - && !match_arm_type_is_optional(t.clone(), scope.clone())) + && !declared_type_carries_optional(t.clone(), scope.clone())) } } @@ -4239,10 +4231,10 @@ pub fn match_arm_mixes_bare_and_optional( arm_type: Rc, scope: Rc, ) -> bool { - ((match_arm_type_is_optional(unified_arm_type.clone(), scope.clone()) + ((declared_type_carries_optional(unified_arm_type.clone(), scope.clone()) && match_arm_type_is_bare_concrete(arm_type.clone(), scope.clone())) || (match_arm_type_is_bare_concrete(unified_arm_type.clone(), scope.clone()) - && match_arm_type_is_optional(arm_type.clone(), scope.clone()))) + && declared_type_carries_optional(arm_type.clone(), scope.clone()))) } pub fn match_arm_join_diagnostics( @@ -4258,26 +4250,21 @@ pub fn match_arm_join_diagnostics( arm.body_type.clone(), scope.clone(), ) { - Rc::new(vec![inference_error( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - "match arms mix a required and an optional type: ".to_string(), - crate::v1_compiler_infer_types::node_type_shape( - unified_arm_type.clone(), - scope.type_env.clone().source_indices.clone(), - ), - ), - " vs ".to_string(), + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { + position: "match arm".to_string(), + expected: crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), ), - crate::v1_compiler_infer_types::node_type_shape( + got: crate::v1_compiler_infer_types::node_type_shape( arm.body_type.clone(), scope.type_env.clone().source_indices.clone(), ), - ), - crate::v1_std_core::arm_body(arm.typed_arm.clone()) - .span - .clone(), + span: crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), + }), scope.module_name.clone(), )]) } else { From bea7b24f00e25ad4d1e0847c70adc7678592a07e Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 07:13:34 +0000 Subject: [PATCH 58/69] C5: the two genuine corpus sites the match-arm wall refuses (oci layer_at passthrough; srv3 optional first() under -> String) Co-Authored-By: Claude Sonnet 5.5 --- dag/extdeps/container/oci/manifest.dag | 5 +---- dag/gunbc/srv3/srv3_os_install_diagnostic.dag | 13 +++++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/dag/extdeps/container/oci/manifest.dag b/dag/extdeps/container/oci/manifest.dag index b69c8b83e7d..adc103f5f88 100644 --- a/dag/extdeps/container/oci/manifest.dag +++ b/dag/extdeps/container/oci/manifest.dag @@ -61,10 +61,7 @@ fn accept_image_manifest(m: ImageManifest) -> ManifestOutcome { } fn layer_at(layers: List, index: Int) -> OciDescriptor? { - match layers |> get(index) { - null => null - other => other - } + layers |> get(index) } fn accept_image_manifest_layers(m: ImageManifest, index: Int) -> ManifestOutcome { diff --git a/dag/gunbc/srv3/srv3_os_install_diagnostic.dag b/dag/gunbc/srv3/srv3_os_install_diagnostic.dag index e569a3be886..94a7fa4ba61 100644 --- a/dag/gunbc/srv3/srv3_os_install_diagnostic.dag +++ b/dag/gunbc/srv3/srv3_os_install_diagnostic.dag @@ -1397,10 +1397,15 @@ fn observe_stdout_bmc_websocket_line(stdout: String) -> String { let parts = split(s: stdout, delimiter: "surface=bmc_websocket") match parts.length() <= 1 { true => concat("", "") - false => { - let tail = parts.skip(n: 1).first() - split(s: tail, delimiter: "\n").first() - } + false => + match parts.skip(n: 1).first() { + Absent => "" + Present { value: tail } => + match split(s: tail, delimiter: "\n").first() { + Absent => "" + Present { value: line } => line + } + } } } From c6f33b696476ee5ee10245483d94276683150b47 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 07:15:08 +0000 Subject: [PATCH 59/69] C5 ruling B: the match-arm wall's claimed scope excludes the Present-payload binding arm; nested-optional failure-mode row; control + narrowness red Co-Authored-By: Claude Sonnet 5.5 --- ...ue_admitted_where_optional_is_declared.dag | 2 ++ ...collapsed_by_infer_carried_by_emission.dag | 22 +++++++++++++++++++ ...f_host_equality_admission_witness_test.dag | 16 ++++++++++++++ src/v1/04_infer.dag | 20 +++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 dag/gunbc/recurring_failure_mode/nested_optional_collapsed_by_infer_carried_by_emission.dag diff --git a/dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag b/dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag index 01f417e8c53..8fdc8de6ed4 100644 --- a/dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag +++ b/dag/gunbc/recurring_failure_mode/bare_value_admitted_where_optional_is_declared.dag @@ -15,6 +15,8 @@ data bare_value_admitted_where_optional_is_declared: RecurringFailureMode = Recu "EVIDENCE: test.claim.self_host_equality_admission_witness. Reds: a bare return, a bare match arm before a none arm, a bare match arm after a none arm, and a bare data initializer, each refused as blocking DeclaredTypeNotInhabited. Controls: an explicit Present return, an absent return, and a Present-spelled data row, all admitted.", + "CLAIMED SCOPE (not a rung drop): the match-arm wall does not judge an arm whose whole body is the payload binding of a Present { value: x } pattern, because infer collapses nested optionality (see nested_optional_collapsed_by_infer_carried_by_emission). The exclusion is pinned by an admitted control and a narrowness red in test.claim.self_host_equality_admission_witness.", + "RUNG FOUND AT: 1 on the Rust emission path (rustc refusal); the interpretation path accepted silently.", "RUNG NOW: 3 at three paths only -- the declared return, the data initializer, and the match-arm join -- each with an enrolled red and positive control. A bare T bound to a T? let annotation, record field, call argument or parameter is a different position whose population this change did not measure, and no rung is claimed there; the class's rung is the minimum across its in-scope paths, so it is not claimed beyond those three.", diff --git a/dag/gunbc/recurring_failure_mode/nested_optional_collapsed_by_infer_carried_by_emission.dag b/dag/gunbc/recurring_failure_mode/nested_optional_collapsed_by_infer_carried_by_emission.dag new file mode 100644 index 00000000000..6d38b09a2dc --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/nested_optional_collapsed_by_infer_carried_by_emission.dag @@ -0,0 +1,22 @@ +module gunbc.recurring_failure_mode.nested_optional_collapsed_by_infer_carried_by_emission + +import std.types { NonEmptyStr } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data nested_optional_collapsed_by_infer_carried_by_emission: RecurringFailureMode = RecurringFailureMode { + identity: "nested_optional_collapsed_by_infer_carried_by_emission" as NonEmptyStr, + + receipts: [ + "Infer carries optionality as one CardOptional flag on a node: join_optional_cardinality merges levels by design and with_required_cardinality strips the flag from a Present payload. So first() over a List is typed T? and the Present payload binding is typed bare T, while the Rust emission carries two levels (Option> and Option). Specimen: gunbc.machine_intake.mtcollins1_boot_diagnostic_bundle first_member_mismatch.", + + "HARM: an infer/emission meaning fork over one fact. Any check built on the single-level reading either refuses a correct program (the match-arm wall at a Present payload arm) or, worse, admits a wrong one silently; the class is silent-wrongness risk, not only a false refusal.", + + "WALL: none. The match-arm wall of bare_value_admitted_where_optional_is_declared excludes an arm whose body is a Present payload binding, as its stated claimed scope.", + + "RUNG FOUND AT: 1 (mitigation by exclusion at one check); no wall claims the nested-optional distinction.", + + "CEILING: 3-4 once optionality is a nested carrier. NEXT-RUNG TRIGGER: a nested-optional carrier in src/v1/00_core.dag, replacing the readers join_optional_cardinality, with_required_cardinality and preserve_outer_optional_cardinality; can climb after that one grounding, assigned as its own lane.", + ], + + evidence: [], +} diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 1d1e64984da..2fadf491f89 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -174,6 +174,22 @@ test fn required_arm_after_none_arm_refuses_blocking() -> Bool { eq_blocking_count(source: return_lift_match_arm_swapped_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 } +// CLAIMED SCOPE of the match-arm wall (ruling B, gunbc#13280): an arm whose whole body is the payload +// binding of `Present { value: x }` is not judged, because infer types that payload single-level (see +// nested_optional_collapsed_by_infer_carried_by_emission). The control is the mtcollins1 shape; the red +// proves the exclusion is narrow: the same arm returning a bare non-binding value still refuses. +data present_payload_arm_control_source: String = "module present_payload_probe\nfn g(xs: List) -> String? {\n match xs.first() {\n Absent => none\n Present { value: r } => r\n }\n}\n" + +data present_payload_arm_narrow_red_source: String = "module present_payload_probe_red\nfn g(xs: List, s: String) -> String? {\n match xs.first() {\n Absent => none\n Present { value: r } => s\n }\n}\n" + +test fn present_payload_binding_arm_stays_admitted() -> Bool { + eq_admitted(source: present_payload_arm_control_source) +} + +test fn present_pattern_arm_with_other_bare_value_still_refuses() -> Bool { + eq_blocking_count(source: present_payload_arm_narrow_red_source, wanted: "DeclaredTypeNotInhabited") >= 1 +} + // THE SAME CLASS AT A DATA INITIALIZER (ruling A on gunbc#13202). A `data r: T? = ` row was // emitted bare against Option<..> and refused only downstream by rustc; the checker now refuses it. // The red's T is a coproduct with a nested-record variant, the specimen that exposed the class; the diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index 24b33fd1392..dbaec8d09de 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -3043,9 +3043,29 @@ fn match_arm_mixes_bare_and_optional(unified_arm_type: Node, arm_type: Node, sco || (match_arm_type_is_bare_concrete(t: unified_arm_type, scope: scope) && declared_type_carries_optional(declared: arm_type, scope: scope)) } +// CLAIMED SCOPE OF THE WALL (not a rung drop): the wall does not judge an arm whose whole body is the +// payload binding of a `Present { value: x }` pattern. Infer types that payload as bare T from a +// scrutinee carried as single-level CardOptional (join_optional_cardinality / with_required_cardinality +// collapse nesting), so over List `first()` yields T? and the payload reads as T though emission +// carries Option>; judging it would refuse a correct arm. Row: +// nested_optional_collapsed_by_infer_carried_by_emission; trigger: a nested-optional carrier in 00_core. +fn match_arm_body_is_present_payload_binding(arm: ArmInferResult, scope: InferScope) -> Bool { + match arm_pattern(n: arm.typed_arm) { + VariantPattern { name: "Present", parent_enum: _, field_bindings: bindings, parent_identity: _ } => + let body_name = expr_var_name_at(texpr: arm_body(n: arm.typed_arm), source_indices: scope.type_env.source_indices) + body_name != "" && (bindings |> any(fb => match field_binding_pattern(n: fb) { + Bind { declaration: declaration } => declaration.name == body_name + _ => false + })) + _ => false + } +} + fn match_arm_join_diagnostics(unified_arm_type: Node, arm: ArmInferResult, scope: InferScope) -> List { if arm_body_diverges(body: arm_body(n: arm.typed_arm)) { [] + } else if match_arm_body_is_present_payload_binding(arm: arm, scope: scope) { + [] } else if match_arm_mixes_bare_and_optional(unified_arm_type: unified_arm_type, arm_type: arm.body_type, scope: scope) { [make_error_node( diagnostic: DeclaredTypeNotInhabited { From c51af47cd83e8c5e8e496669c6852174a7964a10 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 07:41:08 +0000 Subject: [PATCH 60/69] C5 ruling B: bind the variant name (a string-literal variant-pattern field is not emittable) Co-Authored-By: Claude Sonnet 5.5 --- src/v1/04_infer.dag | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index dbaec8d09de..cab2b1285cf 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -3051,9 +3051,9 @@ fn match_arm_mixes_bare_and_optional(unified_arm_type: Node, arm_type: Node, sco // nested_optional_collapsed_by_infer_carried_by_emission; trigger: a nested-optional carrier in 00_core. fn match_arm_body_is_present_payload_binding(arm: ArmInferResult, scope: InferScope) -> Bool { match arm_pattern(n: arm.typed_arm) { - VariantPattern { name: "Present", parent_enum: _, field_bindings: bindings, parent_identity: _ } => + VariantPattern { name: variant_name, parent_enum: _, field_bindings: bindings, parent_identity: _ } => let body_name = expr_var_name_at(texpr: arm_body(n: arm.typed_arm), source_indices: scope.type_env.source_indices) - body_name != "" && (bindings |> any(fb => match field_binding_pattern(n: fb) { + variant_name == "Present" && body_name != "" && (bindings |> any(fb => match field_binding_pattern(n: fb) { Bind { declaration: declaration } => declaration.name == body_name _ => false })) From 61efdc613645106d95d4621da5d69a0b3667a391 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 08:07:08 +0000 Subject: [PATCH 61/69] C5 ruling B: regenerated infer mirror (fixed point) Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_infer.rs | 121 +++++++++++++++++-------- 1 file changed, 81 insertions(+), 40 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index eaf413fdef6..fbb8b0f59ae 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -4237,6 +4237,43 @@ pub fn match_arm_mixes_bare_and_optional( && declared_type_carries_optional(arm_type.clone(), scope.clone()))) } +pub fn match_arm_body_is_present_payload_binding( + arm: Rc, + scope: Rc, +) -> bool { + match (*crate::v1_std_core::arm_pattern(arm.typed_arm.clone())).clone() { + MatchPattern::VariantPattern { + name: variant_name, + field_bindings: bindings, + .. + } => { + let body_name = crate::v1_std_core::expr_var_name_at( + crate::v1_std_core::arm_body(arm.typed_arm.clone()), + scope.type_env.clone().source_indices.clone(), + ); + (((variant_name.clone() == "Present".to_string()) + && (body_name.clone() != "".to_string())) + && { + let mut __found = false; + for fb in bindings.iter().cloned() { + if match (*crate::v1_std_core::field_binding_pattern(fb.clone())).clone() { + MatchPattern::Bind { + declaration: declaration, + .. + } => (declaration.name.clone() == body_name.clone()), + _ => false, + } { + __found = true; + break; + } + } + __found + }) + } + _ => false, + } +} + pub fn match_arm_join_diagnostics( unified_arm_type: Rc, arm: Rc, @@ -4245,58 +4282,62 @@ pub fn match_arm_join_diagnostics( if arm_body_diverges(crate::v1_std_core::arm_body(arm.typed_arm.clone())) { Rc::new(vec![]) } else { - if match_arm_mixes_bare_and_optional( - unified_arm_type.clone(), - arm.body_type.clone(), - scope.clone(), - ) { - Rc::new(vec![crate::v1_std_core::make_error_node( - Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { - position: "match arm".to_string(), - expected: crate::v1_compiler_infer_types::node_type_shape( - unified_arm_type.clone(), - scope.type_env.clone().source_indices.clone(), - ), - got: crate::v1_compiler_infer_types::node_type_shape( - arm.body_type.clone(), - scope.type_env.clone().source_indices.clone(), - ), - span: crate::v1_std_core::arm_body(arm.typed_arm.clone()) - .span - .clone(), - }), - scope.module_name.clone(), - )]) + if match_arm_body_is_present_payload_binding(arm.clone(), scope.clone()) { + Rc::new(vec![]) } else { - if match_arm_types_are_proven_disjoint( + if match_arm_mixes_bare_and_optional( unified_arm_type.clone(), arm.body_type.clone(), scope.clone(), ) { - Rc::new(vec![inference_error( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - "match arms produce proven-disjoint types: ".to_string(), - crate::v1_compiler_infer_types::node_type_shape( - unified_arm_type.clone(), - scope.type_env.clone().source_indices.clone(), - ), - ), - " vs ".to_string(), + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { + position: "match arm".to_string(), + expected: crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), ), - crate::v1_compiler_infer_types::node_type_shape( + got: crate::v1_compiler_infer_types::node_type_shape( arm.body_type.clone(), scope.type_env.clone().source_indices.clone(), ), - ), - crate::v1_std_core::arm_body(arm.typed_arm.clone()) - .span - .clone(), + span: crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), + }), scope.module_name.clone(), )]) } else { - Rc::new(vec![]) + if match_arm_types_are_proven_disjoint( + unified_arm_type.clone(), + arm.body_type.clone(), + scope.clone(), + ) { + Rc::new(vec![inference_error( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + "match arms produce proven-disjoint types: ".to_string(), + crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + ), + " vs ".to_string(), + ), + crate::v1_compiler_infer_types::node_type_shape( + arm.body_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + ), + crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), + scope.module_name.clone(), + )]) + } else { + Rc::new(vec![]) + } } } } From ce5d253897063a8c6dca3d7d44b87caad6b2ed74 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 09:09:33 +0000 Subject: [PATCH 62/69] C5: scope the Present-payload exclusion to the bare-vs-optional check only; the proven-disjoint wall still runs (review of 61efdc6136) Co-Authored-By: Claude Sonnet 5.5 --- .../claim/self_host_equality_admission_witness_test.dag | 8 ++++++++ src/v1/04_infer.dag | 5 ++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 2fadf491f89..2b17a89817b 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -182,6 +182,14 @@ data present_payload_arm_control_source: String = "module present_payload_probe\ data present_payload_arm_narrow_red_source: String = "module present_payload_probe_red\nfn g(xs: List, s: String) -> String? {\n match xs.first() {\n Absent => none\n Present { value: r } => s\n }\n}\n" +// The exclusion switches off ONLY the bare-versus-optional check: a payload-binding arm that is +// genuinely disjoint from its sibling (String vs Int) still reaches the proven-disjoint wall. +data present_payload_arm_disjoint_red_source: String = "module present_payload_probe_disjoint\nfn g(x: Int?) -> String {\n match x {\n Absent => \"s\"\n Present { value: r } => r\n }\n}\n" + +test fn present_payload_arm_disjoint_from_sibling_still_refuses() -> Bool { + eq_census_clean(source: present_payload_arm_disjoint_red_source) == false +} + test fn present_payload_binding_arm_stays_admitted() -> Bool { eq_admitted(source: present_payload_arm_control_source) } diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index cab2b1285cf..01d617ab92b 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -3064,9 +3064,8 @@ fn match_arm_body_is_present_payload_binding(arm: ArmInferResult, scope: InferSc fn match_arm_join_diagnostics(unified_arm_type: Node, arm: ArmInferResult, scope: InferScope) -> List { if arm_body_diverges(body: arm_body(n: arm.typed_arm)) { [] - } else if match_arm_body_is_present_payload_binding(arm: arm, scope: scope) { - [] - } else if match_arm_mixes_bare_and_optional(unified_arm_type: unified_arm_type, arm_type: arm.body_type, scope: scope) { + } else if !match_arm_body_is_present_payload_binding(arm: arm, scope: scope) + && match_arm_mixes_bare_and_optional(unified_arm_type: unified_arm_type, arm_type: arm.body_type, scope: scope) { [make_error_node( diagnostic: DeclaredTypeNotInhabited { position: "match arm", From ab3ef3922ea85e22873591aa3fc22f3b5f0b55d0 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 09:35:11 +0000 Subject: [PATCH 63/69] C5: regenerated infer mirror for the scoped exclusion (fixed point) Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_infer.rs | 86 +++++++++++++------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index fbb8b0f59ae..0ac5431f441 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -4282,62 +4282,60 @@ pub fn match_arm_join_diagnostics( if arm_body_diverges(crate::v1_std_core::arm_body(arm.typed_arm.clone())) { Rc::new(vec![]) } else { - if match_arm_body_is_present_payload_binding(arm.clone(), scope.clone()) { - Rc::new(vec![]) + if (!match_arm_body_is_present_payload_binding(arm.clone(), scope.clone()) + && match_arm_mixes_bare_and_optional( + unified_arm_type.clone(), + arm.body_type.clone(), + scope.clone(), + )) + { + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { + position: "match arm".to_string(), + expected: crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + got: crate::v1_compiler_infer_types::node_type_shape( + arm.body_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + span: crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), + }), + scope.module_name.clone(), + )]) } else { - if match_arm_mixes_bare_and_optional( + if match_arm_types_are_proven_disjoint( unified_arm_type.clone(), arm.body_type.clone(), scope.clone(), ) { - Rc::new(vec![crate::v1_std_core::make_error_node( - Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { - position: "match arm".to_string(), - expected: crate::v1_compiler_infer_types::node_type_shape( - unified_arm_type.clone(), - scope.type_env.clone().source_indices.clone(), + Rc::new(vec![inference_error( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + "match arms produce proven-disjoint types: ".to_string(), + crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + ), + " vs ".to_string(), ), - got: crate::v1_compiler_infer_types::node_type_shape( + crate::v1_compiler_infer_types::node_type_shape( arm.body_type.clone(), scope.type_env.clone().source_indices.clone(), ), - span: crate::v1_std_core::arm_body(arm.typed_arm.clone()) - .span - .clone(), - }), + ), + crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), scope.module_name.clone(), )]) } else { - if match_arm_types_are_proven_disjoint( - unified_arm_type.clone(), - arm.body_type.clone(), - scope.clone(), - ) { - Rc::new(vec![inference_error( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - "match arms produce proven-disjoint types: ".to_string(), - crate::v1_compiler_infer_types::node_type_shape( - unified_arm_type.clone(), - scope.type_env.clone().source_indices.clone(), - ), - ), - " vs ".to_string(), - ), - crate::v1_compiler_infer_types::node_type_shape( - arm.body_type.clone(), - scope.type_env.clone().source_indices.clone(), - ), - ), - crate::v1_std_core::arm_body(arm.typed_arm.clone()) - .span - .clone(), - scope.module_name.clone(), - )]) - } else { - Rc::new(vec![]) - } + Rc::new(vec![]) } } } From d69ccd707e26fb469d54de01af694e2dbcd30820 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Tue, 6 Oct 2026 10:34:24 +0000 Subject: [PATCH 64/69] C5: the disjoint control asserts the proven-disjoint refusal itself (class InternalError, subject names both arm types), not a non-clean census Co-Authored-By: Claude Sonnet 5.5 --- .../self_host_equality_admission_witness_test.dag | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dag/test/claim/self_host_equality_admission_witness_test.dag b/dag/test/claim/self_host_equality_admission_witness_test.dag index 2b17a89817b..64904ed5ebe 100644 --- a/dag/test/claim/self_host_equality_admission_witness_test.dag +++ b/dag/test/claim/self_host_equality_admission_witness_test.dag @@ -27,6 +27,14 @@ fn eq_blocking_count(source: String, wanted: String) -> Int { } } +fn eq_blocking_count_at_subject(source: String, wanted: String, subject: String) -> Int { + match eq_census_of(source: source) { + CensusObserved { rows: rows } => + census_total_count(rows: census_blocking_rows(rows: rows) |> filter(r => (r.diagnostic_class as String) == wanted && r.subject_name == subject)) + CensusNotRunnable { cause: _ } => 0 - 1 + } +} + fn eq_wall_refusal_count(source: String) -> Int { eq_blocking_count(source: source, wanted: "EqualityOnFunctionMember") + eq_blocking_count(source: source, wanted: "EqualityMemberUnjudgeable") @@ -187,7 +195,10 @@ data present_payload_arm_narrow_red_source: String = "module present_payload_pro data present_payload_arm_disjoint_red_source: String = "module present_payload_probe_disjoint\nfn g(x: Int?) -> String {\n match x {\n Absent => \"s\"\n Present { value: r } => r\n }\n}\n" test fn present_payload_arm_disjoint_from_sibling_still_refuses() -> Bool { - eq_census_clean(source: present_payload_arm_disjoint_red_source) == false + eq_blocking_count_at_subject( + source: present_payload_arm_disjoint_red_source, + wanted: "InternalError", + subject: "match arms produce proven-disjoint types: Primitive(String) vs Primitive(Int)") == 1 } test fn present_payload_binding_arm_stays_admitted() -> Bool { From 9abd3969a8d5e365fce96033d9197286b73982d7 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Wed, 7 Oct 2026 06:25:07 +0000 Subject: [PATCH 65/69] Regenerate stage0 mirrors after merging main into C5 (merge+regen only) Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_infer.rs | 226 ++++++++++++++++++++----- 1 file changed, 187 insertions(+), 39 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 9fb3056826f..84e3d42c148 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -4208,6 +4208,72 @@ pub fn match_arm_types_are_proven_disjoint( } } +pub fn match_arm_type_is_bare_concrete(t: Rc, scope: Rc) -> bool { + { + let name = crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + t.clone(), + ); + let generic = ((((t.params.clone().len() as i64) > 0) + || ((t.inferred.clone() != std::option::Option::None) + && crate::v1_std_core::is_compiler_error(t.inferred.clone().clone().unwrap()))) + || match t.inferred.clone().as_deref().cloned() { + Some(InferredNode::TypeVariable { id: _, .. }) => true, + _ => false, + }); + (((name.clone() != "".to_string()) && !generic.clone()) + && !declared_type_carries_optional(t.clone(), scope.clone())) + } +} + +pub fn match_arm_mixes_bare_and_optional( + unified_arm_type: Rc, + arm_type: Rc, + scope: Rc, +) -> bool { + ((declared_type_carries_optional(unified_arm_type.clone(), scope.clone()) + && match_arm_type_is_bare_concrete(arm_type.clone(), scope.clone())) + || (match_arm_type_is_bare_concrete(unified_arm_type.clone(), scope.clone()) + && declared_type_carries_optional(arm_type.clone(), scope.clone()))) +} + +pub fn match_arm_body_is_present_payload_binding( + arm: Rc, + scope: Rc, +) -> bool { + match (*crate::v1_std_core::arm_pattern(arm.typed_arm.clone())).clone() { + MatchPattern::VariantPattern { + name: variant_name, + field_bindings: bindings, + .. + } => { + let body_name = crate::v1_std_core::expr_var_name_at( + crate::v1_std_core::arm_body(arm.typed_arm.clone()), + scope.type_env.clone().source_indices.clone(), + ); + (((variant_name.clone() == "Present".to_string()) + && (body_name.clone() != "".to_string())) + && { + let mut __found = false; + for fb in bindings.iter().cloned() { + if match (*crate::v1_std_core::field_binding_pattern(fb.clone())).clone() { + MatchPattern::Bind { + declaration: declaration, + .. + } => (declaration.name.clone() == body_name.clone()), + _ => false, + } { + __found = true; + break; + } + } + __found + }) + } + _ => false, + } +} + pub fn match_arm_join_diagnostics( unified_arm_type: Rc, arm: Rc, @@ -4216,35 +4282,61 @@ pub fn match_arm_join_diagnostics( if arm_body_diverges(crate::v1_std_core::arm_body(arm.typed_arm.clone())) { Rc::new(vec![]) } else { - if match_arm_types_are_proven_disjoint( - unified_arm_type.clone(), - arm.body_type.clone(), - scope.clone(), - ) { - Rc::new(vec![inference_error( - v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - "match arms produce proven-disjoint types: ".to_string(), - crate::v1_compiler_infer_types::node_type_shape( - unified_arm_type.clone(), - scope.type_env.clone().source_indices.clone(), - ), - ), - " vs ".to_string(), + if (!match_arm_body_is_present_payload_binding(arm.clone(), scope.clone()) + && match_arm_mixes_bare_and_optional( + unified_arm_type.clone(), + arm.body_type.clone(), + scope.clone(), + )) + { + Rc::new(vec![crate::v1_std_core::make_error_node( + Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { + position: "match arm".to_string(), + expected: crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), ), - crate::v1_compiler_infer_types::node_type_shape( + got: crate::v1_compiler_infer_types::node_type_shape( arm.body_type.clone(), scope.type_env.clone().source_indices.clone(), ), - ), - crate::v1_std_core::arm_body(arm.typed_arm.clone()) - .span - .clone(), + span: crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), + }), scope.module_name.clone(), )]) } else { - Rc::new(vec![]) + if match_arm_types_are_proven_disjoint( + unified_arm_type.clone(), + arm.body_type.clone(), + scope.clone(), + ) { + Rc::new(vec![inference_error( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + "match arms produce proven-disjoint types: ".to_string(), + crate::v1_compiler_infer_types::node_type_shape( + unified_arm_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + ), + " vs ".to_string(), + ), + crate::v1_compiler_infer_types::node_type_shape( + arm.body_type.clone(), + scope.type_env.clone().source_indices.clone(), + ), + ), + crate::v1_std_core::arm_body(arm.typed_arm.clone()) + .span + .clone(), + scope.module_name.clone(), + )]) + } else { + Rc::new(vec![]) + } } } } @@ -6255,6 +6347,69 @@ pub fn declared_type_inhabitance( } } +pub fn declared_type_carries_optional(declared: Rc, scope: Rc) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( + declared.clone(), + scope.type_env.clone(), + scope.module_name.clone(), + ); + ((((declared.return_cardinality.clone() == Cardinality::CardOptional) + || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared.clone(), + )) == "Optional".to_string())) + || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( + source_indices.clone(), + declared_peeled.clone(), + )) == "Optional".to_string())) + } +} + +pub fn position_forbids_bare_lift(position: DeclaredTypePosition) -> bool { + match position.clone() { + DeclaredTypePosition::PositionDeclaredReturn => true, + DeclaredTypePosition::PositionDataInitializer => true, + _ => false, + } +} + +pub fn required_produced_at_optional_declared( + declared: Rc, + produced: Rc, + scope: Rc, +) -> bool { + { + let source_indices = scope.type_env.clone().source_indices.clone(); + let declared_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), declared.clone()); + let produced_name = + crate::v1_std_core::authored_name_at(source_indices.clone(), produced.clone()); + let produced_carries_optional = ((produced.return_cardinality.clone() + == Cardinality::CardOptional) + || (crate::v1_std_core::qualified_last_segment(produced_name.clone()) + == "Optional".to_string())); + let produced_is_generic = ((((produced.params.clone().len() as i64) > 0) + || ((produced.inferred.clone() != std::option::Option::None) + && crate::v1_std_core::is_compiler_error( + produced.inferred.clone().clone().unwrap(), + ))) + || match produced.inferred.clone().as_deref().cloned() { + Some(InferredNode::TypeVariable { id: _, .. }) => true, + _ => false, + }); + ((((((declared_type_carries_optional(declared.clone(), scope.clone()) + && !produced_carries_optional.clone()) + && !produced_is_generic.clone()) + && (produced_name.clone() != "".to_string())) + && (declared_name.clone() != "".to_string())) + && !type_node_is_callable(declared.clone())) + && !type_node_is_callable(produced.clone())) + } +} + pub fn optional_produced_at_required_declared( declared: Rc, produced: Rc, @@ -6275,21 +6430,8 @@ pub fn optional_produced_at_required_declared( Some(InferredNode::TypeVariable { id: _, .. }) => true, _ => false, }); - let declared_peeled = crate::v1_compiler_infer_resolve::peel_nominal_alias_identity( - declared.clone(), - scope.type_env.clone(), - scope.module_name.clone(), - ); - let declared_carries_optional = ((((declared.return_cardinality.clone() - == Cardinality::CardOptional) - || (declared_peeled.return_cardinality.clone() == Cardinality::CardOptional)) - || (crate::v1_std_core::qualified_last_segment(declared_name.clone()) - == "Optional".to_string())) - || (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::authored_name_at( - source_indices.clone(), - declared_peeled.clone(), - )) == "Optional".to_string())); - ((((((produced_carries_optional.clone() && !declared_carries_optional.clone()) + ((((((produced_carries_optional.clone() + && !declared_type_carries_optional(declared.clone(), scope.clone())) && !declared_is_generic.clone()) && (declared_name.clone() != "".to_string())) && !type_node_is_callable(declared.clone())) @@ -6302,11 +6444,17 @@ pub fn optional_at_required_obligation_diags( obligation: Rc, scope: Rc, ) -> Rc>> { - if optional_produced_at_required_declared( + if (optional_produced_at_required_declared( obligation.declared.clone(), obligation.produced.clone(), scope.clone(), - ) { + ) || (position_forbids_bare_lift(obligation.position.clone()) + && required_produced_at_optional_declared( + obligation.declared.clone(), + obligation.produced.clone(), + scope.clone(), + ))) + { Rc::new(vec![crate::v1_std_core::make_error_node( Rc::new(CompilerDiagnostic::DeclaredTypeNotInhabited { position: declared_type_position_label( From c2eef2fa23a15c1d84fd572d207fe7d3d93d5f77 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Wed, 7 Oct 2026 07:08:09 +0000 Subject: [PATCH 66/69] Regenerate stage0 mirrors after merging C5 and main into G Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_emit.rs | 58 ++++++++++++++++++++++ src/v1/stage0/src/v1_compiler_emit_rust.rs | 58 ++++++++++++++++------ 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 7700517388f..48bf08130f8 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -1026,6 +1026,64 @@ pub fn emit_data_fields_json( ) } +pub fn emit_declared_optional_row_json( + value: Rc, + inner_type_name: String, + source_indices: Rc>>, + variant_wire: Rc>>, +) -> Rc { + match (*value.expr_data.clone()).clone() { + ExprData::ExprLiteral { ref value, .. } + if matches!(value.as_ref(), LiteralValue::LitNull) => + { + let LiteralValue::LitNull = value.as_ref() else { + unreachable!() + }; + Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }) + } + ExprData::ExprRecordLit { + parent_enum: pe, .. + } => match pe.clone() { + Some(parent) => { + if (crate::v1_std_core::qualified_last_segment(parent.clone()) + == crate::v1_std_core::qualified_last_segment(inner_type_name.clone())) + { + Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("a data row declared ".to_string(), inner_type_name.clone()), "? is initialized with a bare ".to_string()), inner_type_name.clone()), " literal: no declared coercion lifts T into T? (DESIGN 4, 2026-09-26), so spell it Present { value: .. } or none".to_string()), +}) + } else { + match value.children.clone().first().cloned() { + std::option::Option::None => Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }), + Some(payload_field) => { + if ((value.children.clone().len() as i64) == 1) { + emit_data_value_json( + crate::v1_std_core::field_init_node_value( + payload_field.clone(), + ), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat("an optional row's present literal carries ".to_string(), crate::v1_compiler_emit_core_support::to_string((value.children.clone().len() as i64))), " fields; the option's present arm carries exactly its payload".to_string()), +}) + } + } + } + } + } + std::option::Option::None => { + emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()) + } + }, + _ => emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()), + } +} + pub fn emit_data_value_json( value: Rc, source_indices: Rc>>, diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 36578d61440..7c20e1861d6 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -186,13 +186,13 @@ use crate::v1_compiler_emit::ShellResultChannel::{ pub use crate::v1_compiler_emit::{ bind_operation_transport, child_from_key, compute_service_fields, effective_operation_transport, emit_bin_op_symbol, emit_container, emit_data_value_json, - emit_error_expr, emit_ident, emit_keyed_container_type, emit_keyword, emit_lambda, - emit_lambda_params, emit_let_binding, emit_let_binding_annotated, emit_list_lit_expr, - emit_literal, emit_node_type, emit_null_coalesce, emit_return, emit_shared_expr, - emit_shared_tco_expr, emit_simple_expr, emit_string_literal, emit_typed_cast_shared, - emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, escape_rust_interp_text, - extract_modifier_names, has_nested_records_node, has_service_items, is_null_coalesce, - is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, + emit_declared_optional_row_json, emit_error_expr, emit_ident, emit_keyed_container_type, + emit_keyword, emit_lambda, emit_lambda_params, emit_let_binding, emit_let_binding_annotated, + emit_list_lit_expr, emit_literal, emit_node_type, emit_null_coalesce, emit_return, + emit_shared_expr, emit_shared_tco_expr, emit_simple_expr, emit_string_literal, + emit_typed_cast_shared, emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, + escape_rust_interp_text, extract_modifier_names, has_nested_records_node, has_service_items, + is_null_coalesce, is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, lookup_item_by_identity, module_emit_scope, order_typed_call_args_from_semantics, render_node_type, render_tuple_parts, rust_literal_for_pattern, scope_after_expr, seed_bindings, service_fallback_transport, service_field_ctors, service_field_decls, @@ -40076,18 +40076,21 @@ pub fn emit_data_def( annotation_type_node.clone(), scope.type_env.clone().source_indices.clone(), ) { - crate::v1_compiler_coercion::coerce_primitive_type( - crate::v1_compiler_coercion::type_reference_realization( - annotation_type_node.clone(), + rust_carrier_optional_wrap( + annotation_type_node.clone(), + crate::v1_compiler_coercion::coerce_primitive_type( + crate::v1_compiler_coercion::type_reference_realization( + annotation_type_node.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + annotation_type_node.clone(), + ), + RenderTarget::Rust, + ), crate::v1_std_core::authored_name_at( scope.type_env.clone().source_indices.clone(), annotation_type_node.clone(), ), - RenderTarget::Rust, - ), - crate::v1_std_core::authored_name_at( - scope.type_env.clone().source_indices.clone(), - annotation_type_node.clone(), ), ) } else { @@ -40242,6 +40245,10 @@ pub fn data_row_type_forbids_deserialize( ) } +pub fn data_row_declares_optional(type_node: Rc) -> bool { + (type_node.return_cardinality.clone() == Cardinality::CardOptional) +} + pub fn emit_data_def_body( type_node: Rc, value: Rc, @@ -40428,10 +40435,29 @@ pub fn emit_data_def_body( scope.type_env.clone().source_indices.clone(), )) { - match (*crate::v1_compiler_emit::emit_data_value_json(value.clone(), scope.type_env.clone().source_indices.clone(), emit_info.data_variant_wire_spellings.clone())).clone() { + { + let row_json = if data_row_declares_optional(type_node.clone()) { + crate::v1_compiler_emit::emit_declared_optional_row_json( + value.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + type_node.clone(), + ), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + } else { + crate::v1_compiler_emit::emit_data_value_json( + value.clone(), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + }; + match (*row_json.clone()).clone() { EmitterOutcome::Refused { reason: r, .. } => v1_rt::concat(v1_rt::concat(" compile_error!(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(r.clone())), "\")".to_string()), EmitterOutcome::Emitted { json: json_str, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(" serde_json::from_str(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(json_str.clone())), "\")\n".to_string()), " .expect(\"valid data definition\")".to_string()), } + } } else { { let is_map = crate::v1_compiler_infer_types::node_is_keyed_collection( From a116850bcaf31477faddc0e720f44acf81dc738e Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 8 Oct 2026 04:54:53 +0000 Subject: [PATCH 67/69] Close optional_data_row_cases after the merge join Co-Authored-By: Claude Sonnet 5.5 --- dag/gunbc/instruments/native_emission_controls.dag | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index 0bf8867c044..7244a009498 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -275,6 +275,10 @@ fn optional_data_row_cases() -> List { NativeEmissionCase { identity: "optional_data_row_red_absent_answers_absent", held: control_optional_brand_value(d: control_optional_brand_absent) == "" + } + ] +} + // RULE: an effectful function's return type is rendered against the module's type environment // (v1.compiler.emit_rust emit_func_inferred through render_rust_fn_sig_type), the same authority a // pure function's return uses. It rendered with an empty emit info, so a type argument was judged From 19b1d3cc7cef2755deacbac5849393c4ae181f63 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Thu, 8 Oct 2026 06:11:35 +0000 Subject: [PATCH 68/69] Regenerate emit_rust mirror for optional data rows keep ? Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 58 ++++++++++++++++------ 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 052115df96b..08a64fd57b6 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -186,13 +186,13 @@ use crate::v1_compiler_emit::ShellResultChannel::{ pub use crate::v1_compiler_emit::{ bind_operation_transport, child_from_key, compute_service_fields, effective_operation_transport, emit_bin_op_symbol, emit_container, emit_data_value_json, - emit_error_expr, emit_ident, emit_keyed_container_type, emit_keyword, emit_lambda, - emit_lambda_params, emit_let_binding, emit_let_binding_annotated, emit_list_lit_expr, - emit_literal, emit_node_type, emit_null_coalesce, emit_return, emit_shared_expr, - emit_shared_tco_expr, emit_simple_expr, emit_string_literal, emit_typed_cast_shared, - emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, escape_rust_interp_text, - extract_modifier_names, has_nested_records_node, has_service_items, is_null_coalesce, - is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, + emit_declared_optional_row_json, emit_error_expr, emit_ident, emit_keyed_container_type, + emit_keyword, emit_lambda, emit_lambda_params, emit_let_binding, emit_let_binding_annotated, + emit_list_lit_expr, emit_literal, emit_node_type, emit_null_coalesce, emit_return, + emit_shared_expr, emit_shared_tco_expr, emit_simple_expr, emit_string_literal, + emit_typed_cast_shared, emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, + escape_rust_interp_text, extract_modifier_names, has_nested_records_node, has_service_items, + is_null_coalesce, is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, lookup_item_by_identity, module_emit_scope, order_typed_call_args_from_semantics, render_node_type, render_tuple_parts, rust_literal_for_pattern, scope_after_expr, seed_bindings, service_fallback_transport, service_field_ctors, service_field_decls, @@ -40082,18 +40082,21 @@ pub fn emit_data_def( annotation_type_node.clone(), scope.type_env.clone().source_indices.clone(), ) { - crate::v1_compiler_coercion::coerce_primitive_type( - crate::v1_compiler_coercion::type_reference_realization( - annotation_type_node.clone(), + rust_carrier_optional_wrap( + annotation_type_node.clone(), + crate::v1_compiler_coercion::coerce_primitive_type( + crate::v1_compiler_coercion::type_reference_realization( + annotation_type_node.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + annotation_type_node.clone(), + ), + RenderTarget::Rust, + ), crate::v1_std_core::authored_name_at( scope.type_env.clone().source_indices.clone(), annotation_type_node.clone(), ), - RenderTarget::Rust, - ), - crate::v1_std_core::authored_name_at( - scope.type_env.clone().source_indices.clone(), - annotation_type_node.clone(), ), ) } else { @@ -40248,6 +40251,10 @@ pub fn data_row_type_forbids_deserialize( ) } +pub fn data_row_declares_optional(type_node: Rc) -> bool { + (type_node.return_cardinality.clone() == Cardinality::CardOptional) +} + pub fn emit_data_def_body( type_node: Rc, value: Rc, @@ -40434,10 +40441,29 @@ pub fn emit_data_def_body( scope.type_env.clone().source_indices.clone(), )) { - match (*crate::v1_compiler_emit::emit_data_value_json(value.clone(), scope.type_env.clone().source_indices.clone(), emit_info.data_variant_wire_spellings.clone())).clone() { + { + let row_json = if data_row_declares_optional(type_node.clone()) { + crate::v1_compiler_emit::emit_declared_optional_row_json( + value.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + type_node.clone(), + ), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + } else { + crate::v1_compiler_emit::emit_data_value_json( + value.clone(), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + }; + match (*row_json.clone()).clone() { EmitterOutcome::Refused { reason: r, .. } => v1_rt::concat(v1_rt::concat(" compile_error!(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(r.clone())), "\")".to_string()), EmitterOutcome::Emitted { json: json_str, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(" serde_json::from_str(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(json_str.clone())), "\")\n".to_string()), " .expect(\"valid data definition\")".to_string()), } + } } else { { let is_map = crate::v1_compiler_infer_types::node_is_keyed_collection( From 019cbc4d8290bdd9cd1c1c7ac422cb99a8c3e4a5 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Fri, 9 Oct 2026 02:31:29 +0000 Subject: [PATCH 69/69] Regenerate emit and emit_rust mirrors after merging main Co-Authored-By: Claude Sonnet 5.5 --- src/v1/stage0/src/v1_compiler_emit.rs | 58 ++++++++++++++++++++++ src/v1/stage0/src/v1_compiler_emit_rust.rs | 58 ++++++++++++++++------ 2 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit.rs b/src/v1/stage0/src/v1_compiler_emit.rs index 7700517388f..48bf08130f8 100644 --- a/src/v1/stage0/src/v1_compiler_emit.rs +++ b/src/v1/stage0/src/v1_compiler_emit.rs @@ -1026,6 +1026,64 @@ pub fn emit_data_fields_json( ) } +pub fn emit_declared_optional_row_json( + value: Rc, + inner_type_name: String, + source_indices: Rc>>, + variant_wire: Rc>>, +) -> Rc { + match (*value.expr_data.clone()).clone() { + ExprData::ExprLiteral { ref value, .. } + if matches!(value.as_ref(), LiteralValue::LitNull) => + { + let LiteralValue::LitNull = value.as_ref() else { + unreachable!() + }; + Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }) + } + ExprData::ExprRecordLit { + parent_enum: pe, .. + } => match pe.clone() { + Some(parent) => { + if (crate::v1_std_core::qualified_last_segment(parent.clone()) + == crate::v1_std_core::qualified_last_segment(inner_type_name.clone())) + { + Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("a data row declared ".to_string(), inner_type_name.clone()), "? is initialized with a bare ".to_string()), inner_type_name.clone()), " literal: no declared coercion lifts T into T? (DESIGN 4, 2026-09-26), so spell it Present { value: .. } or none".to_string()), +}) + } else { + match value.children.clone().first().cloned() { + std::option::Option::None => Rc::new(EmitterOutcome::Emitted { + json: "null".to_string(), + }), + Some(payload_field) => { + if ((value.children.clone().len() as i64) == 1) { + emit_data_value_json( + crate::v1_std_core::field_init_node_value( + payload_field.clone(), + ), + source_indices.clone(), + variant_wire.clone(), + ) + } else { + Rc::new(EmitterOutcome::Refused { + reason: v1_rt::concat(v1_rt::concat("an optional row's present literal carries ".to_string(), crate::v1_compiler_emit_core_support::to_string((value.children.clone().len() as i64))), " fields; the option's present arm carries exactly its payload".to_string()), +}) + } + } + } + } + } + std::option::Option::None => { + emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()) + } + }, + _ => emit_data_value_json(value.clone(), source_indices.clone(), variant_wire.clone()), + } +} + pub fn emit_data_value_json( value: Rc, source_indices: Rc>>, diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index e28b0327929..d24afa5a95e 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -186,13 +186,13 @@ use crate::v1_compiler_emit::ShellResultChannel::{ pub use crate::v1_compiler_emit::{ bind_operation_transport, child_from_key, compute_service_fields, effective_operation_transport, emit_bin_op_symbol, emit_container, emit_data_value_json, - emit_error_expr, emit_ident, emit_keyed_container_type, emit_keyword, emit_lambda, - emit_lambda_params, emit_let_binding, emit_let_binding_annotated, emit_list_lit_expr, - emit_literal, emit_node_type, emit_null_coalesce, emit_return, emit_shared_expr, - emit_shared_tco_expr, emit_simple_expr, emit_string_literal, emit_typed_cast_shared, - emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, escape_rust_interp_text, - extract_modifier_names, has_nested_records_node, has_service_items, is_null_coalesce, - is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, + emit_declared_optional_row_json, emit_error_expr, emit_ident, emit_keyed_container_type, + emit_keyword, emit_lambda, emit_lambda_params, emit_let_binding, emit_let_binding_annotated, + emit_list_lit_expr, emit_literal, emit_node_type, emit_null_coalesce, emit_return, + emit_shared_expr, emit_shared_tco_expr, emit_simple_expr, emit_string_literal, + emit_typed_cast_shared, emit_typed_if_shared, emit_typed_let_shared, emit_unary_op, + escape_rust_interp_text, extract_modifier_names, has_nested_records_node, has_service_items, + is_null_coalesce, is_self_recursive, is_tco_eligible, keyed_container_has_target_inhabitant, lookup_item_by_identity, module_emit_scope, order_typed_call_args_from_semantics, render_node_type, render_tuple_parts, rust_literal_for_pattern, scope_after_expr, seed_bindings, service_fallback_transport, service_field_ctors, service_field_decls, @@ -40085,18 +40085,21 @@ pub fn emit_data_def( annotation_type_node.clone(), scope.type_env.clone().source_indices.clone(), ) { - crate::v1_compiler_coercion::coerce_primitive_type( - crate::v1_compiler_coercion::type_reference_realization( - annotation_type_node.clone(), + rust_carrier_optional_wrap( + annotation_type_node.clone(), + crate::v1_compiler_coercion::coerce_primitive_type( + crate::v1_compiler_coercion::type_reference_realization( + annotation_type_node.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + annotation_type_node.clone(), + ), + RenderTarget::Rust, + ), crate::v1_std_core::authored_name_at( scope.type_env.clone().source_indices.clone(), annotation_type_node.clone(), ), - RenderTarget::Rust, - ), - crate::v1_std_core::authored_name_at( - scope.type_env.clone().source_indices.clone(), - annotation_type_node.clone(), ), ) } else { @@ -40251,6 +40254,10 @@ pub fn data_row_type_forbids_deserialize( ) } +pub fn data_row_declares_optional(type_node: Rc) -> bool { + (type_node.return_cardinality.clone() == Cardinality::CardOptional) +} + pub fn emit_data_def_body( type_node: Rc, value: Rc, @@ -40437,10 +40444,29 @@ pub fn emit_data_def_body( scope.type_env.clone().source_indices.clone(), )) { - match (*crate::v1_compiler_emit::emit_data_value_json(value.clone(), scope.type_env.clone().source_indices.clone(), emit_info.data_variant_wire_spellings.clone())).clone() { + { + let row_json = if data_row_declares_optional(type_node.clone()) { + crate::v1_compiler_emit::emit_declared_optional_row_json( + value.clone(), + crate::v1_std_core::authored_name_at( + scope.type_env.clone().source_indices.clone(), + type_node.clone(), + ), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + } else { + crate::v1_compiler_emit::emit_data_value_json( + value.clone(), + scope.type_env.clone().source_indices.clone(), + emit_info.data_variant_wire_spellings.clone(), + ) + }; + match (*row_json.clone()).clone() { EmitterOutcome::Refused { reason: r, .. } => v1_rt::concat(v1_rt::concat(" compile_error!(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(r.clone())), "\")".to_string()), EmitterOutcome::Emitted { json: json_str, .. } => v1_rt::concat(v1_rt::concat(v1_rt::concat(" serde_json::from_str(\"".to_string(), crate::v1_compiler_emit_core_support::escape_string_literal_body(json_str.clone())), "\")\n".to_string()), " .expect(\"valid data definition\")".to_string()), } + } } else { { let is_map = crate::v1_compiler_infer_types::node_is_keyed_collection(