Skip to content
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ data expression_enclosing_a_block_headed_operand_lowers_to_that_block_at_v2_body
"RECEIPTS. Fixtures, traced by a scratch normalized-tree dump over `v2.compiler.program_assembly` `program_assembly_phase_normalize` at main 8bf4b66774c, and by the census line of each: all six forms above lower to the block alone. The block as LEFT operand (`match w {..} && t`) and the parenthesised form (`t && (match w {..})`) are REFUSED at normalize, not dropped. Census: `v2.compiler.reference_conservation_census` `reference_conservation_census_for_paths` over `reference_conservation_stratified_sample_paths` at 69e0bb7566e. Around 113 atoms absent in accepted modules sit in a && or || chain beside a block, plus the largest residue declarations: `v2.std.float` `float_body_compare_ieee_ordered_outcome` (`Accepted { value: match a {..}, diagnostics: None }`) and `test.claim.codex_package_delivery_wet_witness_test`, whose witnesses are `&& match ..` chains, so a claim there can hold on its last conjunct alone.",
"DISTINGUISHING FACTS. Not `lowering_accessor_collapses_a_sequence_operand`, which keeps the LEFT element of an operand; here the block is kept and the enclosing expression is lost. Not gunbc#11911, a parse-order defect; here the parse accepts. Not `match_arms_after_the_second_are_dropped_at_v2_body_lowering`, which loses arms INSIDE a match; this loses what is AROUND it.",
"RUNG FOUND AT: below the floor (silent wrongness). CEILING: structurally guaranteed. An expression lowers to its own operator, construct or application over every constituent, or refuses at the constituent it could not read. A control form is lowered as the whole value only where it IS the value. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: v2 body lowering has no reader that answers a value by searching its subtree for a control form, so an enclosing expression the fold left unlowered refuses instead of being replaced. Owner: bright-boar-848's fold queue (quiet-seal-543, 2026-09-25). The fall-back reader is that lane's subject. Pinned drops, each holding while the drop happens and redding when the repair lands, in `v2.test.claim.namespace_xl0.reference_conservation_accepted_drops`: `a_binary_operand_beside_a_match_is_reported_dropped_holds`, `a_binary_operand_beside_an_if_is_reported_dropped_holds`, `a_record_field_beside_a_match_valued_field_is_reported_dropped_holds`, `a_call_argument_beside_a_match_valued_argument_is_reported_dropped_holds`. The census's clean control, `v2.test.claim.namespace_xl0.reference_conservation` `the_clean_control_conserves_every_authored_atom_holds`, is the neighbour that conserves.",
"CLIMBED, THE TRIGGER CAPABILITY MET (bright-boar-848, XL-2). Two links, both in `v2.compiler.body_lowering_fold`. (1) `body_lower_find_control_form_optional` no longer searches a value's subtree: it descends only through what does not change the expression -- a production to its captured child, a sequence whose right side is an empty tail, a lone opening or closing delimiter -- so a control form is lowered as the whole value only where it IS the value, and an enclosing operator, call or record goes whole to the binary/postfix route. (2) That route then exposed the second link: `body_lower_primary_expr` ran its raw-syntax strategy readers over a capture the bottom-up fold had ALREADY lowered (a Match or Branch) and one answered it with its first child, so `t && match w {..}` became `t && w`. Measured by calling `body_lower_value_read` at each production level of the operand: correct at the match_expr node, collapsed from its primary parent up. A primary whose capture is core substrate is now that node, the rule `body_lower_postfix_lowered_primary_optional` already states one level up. The four pinned drops flip to conservation controls (accepted AND the enclosing constituent not dropped), red against the base fold and green after. The label and let-binder atoms that stay absent in the same fixtures are the separately declared NamedArgumentLabel and StatementLetBinder drops. RUNG NOW: structurally guaranteed for the enclosing expression.",
],

evidence: [
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_binary_operand_beside_a_match_is_reported_dropped_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_binary_operand_beside_an_if_is_reported_dropped_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_record_field_beside_a_match_valued_field_is_reported_dropped_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_call_argument_beside_a_match_valued_argument_is_reported_dropped_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_binary_operand_beside_a_match_is_conserved_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_binary_operand_beside_an_if_is_conserved_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_record_field_beside_a_match_valued_field_is_conserved_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_call_argument_beside_a_match_valued_argument_is_conserved_holds", field: WholeDeclaration },
],
}
77 changes: 52 additions & 25 deletions src/v2/compiler/body_lowering_fold.dag
Original file line number Diff line number Diff line change
Expand Up @@ -2872,11 +2872,16 @@ fn body_lower_body_subtree_lower(captured: Node) -> Outcome<Optional<Node>> {
}
}

// THE OUTERMOST CONTROL FORM, NOT THE FIRST OF A FIXED KIND. The four control productions were
// searched one kind at a time, each search deep, so a body `match c { A(x) => if p { .. } .. }`
// was answered by the `if` inside its arm -- the whole match, both arms and the binder, gone --
// because `if` was searched before `match`. One pre-order walk over the four kinds finds the
// form nearest the root, which on an expression spine is the one that owns the body.
// A CONTROL FORM IS TAKEN ONLY WHEN IT IS THE EXPRESSION. The walk descends through what does not
// change the expression -- a production to its captured child, a sequence whose right side is an
// empty tail, and a lone opening or closing delimiter around it (`( .. )`, `{ .. }`) -- and stops
// anywhere else. It used to walk the whole capture pre-order and answer the FIRST if / match / loop /
// let anywhere beneath it, so `t && match w {..}`, `f(a: match ..)`, `x + if c {..} else {..}` and
// `R { v: if .. }` each lowered to the nested block alone and the enclosing operator, call or record
// was dropped with no diagnostic (gunbc.recurring_failure_mode
// expression_enclosing_a_block_headed_operand_lowers_to_that_block). An expression that is not a
// control form goes whole to body_lower_body_subtree_lower_from_binary, and a block nested inside it
// is reached as that expression's operand, argument or field value.
type ControlFormFound {
emitted: Symbol
captured: Node
Expand All @@ -2889,35 +2894,45 @@ fn body_lower_is_control_form_emitted(id: Symbol) -> Bool {
|| (id == ^dag_surface_let_expr)
}

fn body_lower_node_is_delimiter_atom(n: Node, opening: Bool) -> Bool {
match node_atom_identity_optional(node: body_lower_deep_unwrap_optional(node: n)) {
Present { value: id } =>
if opening { (id == ^dag_token_lparen) || (id == ^dag_token_lbrace) } else { (id == ^dag_token_rparen) || (id == ^dag_token_rbrace) }
Absent => false
}
}

fn body_lower_find_control_form_optional(root: Node) -> Optional<ControlFormFound> {
match parse_production_emitted_identity_optional(node: root) {
Present { value: id } =>
match body_lower_is_control_form_emitted(id: id) {
true =>
match parse_production_captured_child_optional(node: root) {
Present { value: captured } =>
optional_present(value: ControlFormFound { emitted: id, captured: captured })
Absent => body_lower_find_control_form_under_children(root: root)
match parse_production_captured_child_optional(node: root) {
Absent => optional_absent()
Present { value: captured } =>
if body_lower_is_control_form_emitted(id: id) {
optional_present(value: ControlFormFound { emitted: id, captured: captured })
} else if body_lower_find_captured_prunable(id: id) {
optional_absent()
} else {
body_lower_find_control_form_optional(root: captured)
}
false =>
match body_lower_find_captured_prunable(id: id) {
true => optional_absent()
false => body_lower_find_control_form_under_children(root: root)
}
Absent =>
match sugar_sequence_pair_optional(node: root) {
Absent => optional_absent()
Present { value: pair } =>
if is_empty_conj_root(n: body_lower_deep_unwrap_optional(node: pair.right)) {
body_lower_find_control_form_optional(root: pair.left)
} else if body_lower_node_is_delimiter_atom(n: pair.right, opening: false) {
body_lower_find_control_form_optional(root: pair.left)
} else if body_lower_node_is_delimiter_atom(n: pair.left, opening: true) {
body_lower_find_control_form_optional(root: pair.right)
} else {
optional_absent()
}
}
Absent => body_lower_find_control_form_under_children(root: root)
}
}

fn body_lower_find_control_form_under_children(root: Node) -> Optional<ControlFormFound> {
fold(root.children, init: Absent, f: fn(acc, edge) {
match acc {
Present { value: _ } => acc
Absent => body_lower_find_control_form_optional(root: edge.target)
}
})
}

fn body_lower_body_subtree_lower_control_forms(captured: Node) -> Outcome<Optional<Node>> {
match body_lower_find_control_form_optional(root: captured) {
Absent => body_lower_body_subtree_lower_from_binary(captured: captured)
Expand Down Expand Up @@ -7735,11 +7750,22 @@ fn body_lower_list_literal(literal: Node, items_capture: Node) -> Outcome<Node>
)
}

// A CAPTURE THE FOLD ALREADY LOWERED IS THE PRIMARY'S VALUE. body_lower_fold_reduce folds a node's
// children before reducing it, so a primary whose capture is a control form -- `match w {..}`,
// `if c {..} else {..}` in operand, argument or field position -- reaches this reducer holding the
// lowered Match or Branch, not syntax. The strategy readers below read raw syntax: handed a lowered
// node, one of them answered it with its first child, so `t && match w {..}` lowered to `t && w`
// with every arm dropped (the value reader on the match_expr node itself was correct; on its primary
// parent it was not). The postfix reducer already passes a lowered primary through
// (body_lower_postfix_lowered_primary_optional); this is the same rule one level down.
fn body_lower_primary_expr(shell: Node) -> Outcome<Node> {
let captured = match body_lower_unwrap_captured(shell: shell) {
Present { value: inner } => inner
Absent => shell
}
if body_lower_is_core_substrate(node: captured) {
outcome_accepted(value: captured)
} else {
match body_lower_int_literal_with_magnitude_optional(node: captured) {
Present { value: lit } => outcome_accepted(value: lit)
Absent =>
Expand Down Expand Up @@ -7819,6 +7845,7 @@ fn body_lower_primary_expr(shell: Node) -> Outcome<Node> {
}
}
}
}
}

fn body_lower_fn_body_shell(shell: Node) -> Outcome<BodyLowering> {
Expand Down
Loading
Loading