Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ data data_initializer_match_reads_its_scrutinee_from_an_arm_at_v2_body_lowering:
"WHERE, cited by symbol, traced (a normalized-tree dump of the fixture shows the scrutinee edge holding `dag_token_kw_true` at the first arm body's occurrence). `v2.compiler.body_lowering_fold` `body_lower_match_scrutinee_optional` finds the scrutinee by searching the WHOLE match subtree for the first `dag_surface_binary_expr`, then `dag_surface_postfix_expr` (`body_lower_find_captured`). A data initializer is folded bottom-up before the declaration is dispatched (`body_lower_data_initializer_body`'s own note), so by then the scrutinee's shell has been reduced and is no longer that production. The search therefore finds the next one, inside an arm body. That is a positional fact obtained by searching for its shape (`a_positional_fact_is_obtained_by_searching_for_its_shape`'s class), at a new site.",
"RECEIPTS. Census rerun on the #12313 lexer (exact loci): 13 of the 3,472 atoms absent in accepted modules have a production chain `data_decl/expr/match_expr/binary_expr...` (the scrutinee position), which is exact at chain grain, all in `test.claim.manual.outcome_diagnostics_eq` `witness_diagnostics_merge_some`. Fixtures: a call scrutinee with record arguments and one with plain arguments both drop; the fn-body form drops only the argument label, which is a separate row.",
"RUNG FOUND AT: below the floor (silent wrongness). CEILING: structurally guaranteed. The scrutinee is read from its grammar position, the child after `match`, or the match refuses. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: v2 body lowering reads a match's scrutinee positionally on every route, data initializers included, never by searching the match subtree. Owner: bright-boar-848's fold queue. The pinned drop claim holds while the drop happens and reds when the repair lands.",
"CLIMBED, THE TRIGGER CAPABILITY MET (lively-bear-30, XL-2). `v2.compiler.body_lowering_fold` `body_lower_match_scrutinee_optional` reads the scrutinee from its grammar position -- match_expr is seq(`match`, seq(binary_expr, seq(`{`, ..))), so it is the left of the spine's right after the `match` keyword -- on every route, and a spine not headed by `match` answers Absent, which the caller refuses as match_arm_navigation_refused. The subtree search and its spine-walk fallback (`body_lower_match_scrutinee_from_spine`, `body_lower_match_scrutinee_on_token`) are deleted. The position holds on the data route, whose scrutinee shell the fold has already reduced, because `body_lower_match_scrutinee_value` reads an already-lowered node as it stands. The pinned drop flips to a conservation control (accepted AND neither the scrutinee argument nor its callee dropped), red against the base fold and green after. Its pair is the same match as a fn body, which conserves on both sides (`the_same_match_as_a_fn_body_conserves_its_scrutinee_holds`). The shape is read by `v2.test.claim.body_lowering.match_position_structure`: the data route's Match has the authored call as its first positional child, red against the base fold, with the fn-route twin green on both sides. RUNG NOW: structurally guaranteed.",
],

evidence: [
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_data_initializer_match_scrutinee_is_reported_dropped_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_data_initializer_match_scrutinee_is_conserved_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "the_same_match_as_a_fn_body_conserves_its_scrutinee_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.body_lowering.match_position_structure", decl_name: "a_data_initializer_match_lowers_its_scrutinee_from_the_match_position_holds", field: WholeDeclaration },
],
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ data match_arm_statement_body_lowers_to_its_first_expression_at_v2_body_lowering
"WHERE, cited by symbol. `v2.compiler.body_lowering_fold` `body_lower_match_arm_body_capture_optional` answers the arm body with the first `dag_surface_expr` it finds in the subtree (`body_lower_find_captured`, a pre-order first match). For a `dag_surface_match_arm_stmt_body`, the first expr is the let's value. The `let` and the continuation are never read. This is one of the first-match readers in bright-boar-848's fold-cleanup lane.",
"RECEIPTS. Fixture traced by the census at the #12313 head: `X => let t = zq / g(a: zr)` drops `t`, `g` and `zr`; with a nested match as the continuation, its scrutinee and arms are dropped too. Census: `v2.compiler.reference_conservation_census` `reference_conservation_census_for_paths` over `reference_conservation_stratified_sample_paths`, rerun on the #12313 lexer (exact loci). 29 of the 3,472 atoms absent in accepted modules have a production chain through `match_arm/stmt`, which is exact at chain grain; one of them is `test.claim.sql_create_table_fold_test` `sql_fold_fold_serialize`. DISTINGUISHING FACTS: not `lowering_rebuilds_an_authored_atom_without_its_occurrence`'s let binder, where the binder is kept at the let shell's occurrence; here the continuation is lost too. Not `match_arms_after_the_second_are_dropped_at_v2_body_lowering`: the arm is present, but its body is truncated.",
"RUNG FOUND AT: below the floor (silent wrongness). CEILING: structurally guaranteed. An arm body lowers to the bind-and-continue form its statements denote, or refuses at the statement it could not read. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: v2 body lowering reads a match arm's statement body through the statement authority that fn bodies use, not by searching for an expression. Owner: bright-boar-848's fold queue. The pinned drop claim holds while the drop happens and reds when the repair lands.",
"CLIMBED, THE TRIGGER CAPABILITY MET (lively-bear-30, XL-2). Two readings in `v2.compiler.body_lowering_fold`. (1) `body_lower_match_arm_body_capture_optional` reads the arm body from its grammar position, the right of the `=>`, instead of the first expr, primary or postfix found in the arm. (2) `body_lower_match_arm_body_lowered`, which both arm routes now call, lowers a statement body through `body_lower_stmt_spine`, the authority a fn body and an if arm use: a let binds the rest, the last statement is the value, any other statement preceding another refuses located. The grammar's match_arm_stmt_body production is realized UNWRAPPED by `v2.compiler.parse` `parse_match_arm_stmt_body` (a parsed arm is `=>` followed directly by its `stmt` productions, with no production shell), so the statement body is recognized by what it is, a spine headed by a `stmt` production with a successor (`body_lower_match_arm_statement_spine_optional`). The pinned drop flips to a conservation control (accepted AND neither the continuation's argument nor the let's value dropped), red against the base fold and green after. The shape is read by `v2.test.claim.body_lowering.match_position_structure` `a_match_arm_statement_body_lowers_to_the_let_binding_its_continuation_holds`: the arm body is a Bind of key, value and continuation in that order, so a swapped value and continuation reds it. RUNG NOW: structurally guaranteed.",
],

evidence: [
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_statement_after_a_let_in_a_match_arm_is_reported_dropped_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.namespace_xl0.reference_conservation_accepted_drops", decl_name: "a_statement_after_a_let_in_a_match_arm_is_conserved_holds", field: WholeDeclaration },
DeclarationRef { module_path: "v2.test.claim.body_lowering.match_position_structure", decl_name: "a_match_arm_statement_body_lowers_to_the_let_binding_its_continuation_holds", field: WholeDeclaration },
],
}
162 changes: 93 additions & 69 deletions src/v2/compiler/body_lowering_fold.dag
Original file line number Diff line number Diff line change
Expand Up @@ -5396,22 +5396,29 @@ fn body_lower_match_arm_navigation_reject(arm_capture: Node) -> Outcome<Node> {
)
}

// THE ARM BODY IS READ FROM ITS GRAMMAR POSITION: match_arm is seq(pattern, seq(`=>`, body)), so the
// body is the right of the `=>`. It was the first dag_surface_expr, then primary_expr, then
// postfix_expr found anywhere in the arm (body_lower_find_captured, a pre-order first match). For
// an arm whose body is a statement sequence -- `X => let t = v` then `e` -- the first expr is the
// let's value, so the arm lowered to `v`, and the binder and every later statement were gone with no
// diagnostic (gunbc.recurring_failure_mode
// match_arm_statement_body_lowers_to_its_first_expression_at_v2_body_lowering). An arm whose `=>`
// is not at its position answers Absent, and its caller refuses the arm's navigation.
fn body_lower_match_arm_body_capture_optional(stripped: Node) -> Optional<Node> {
match body_lower_find_captured(root: stripped, emitted: ^dag_surface_expr) {
ParseSubtreeFound { captured: expr } => optional_present(value: expr)
ParseSubtreeAbsent =>
match body_lower_find_captured(
root: stripped,
emitted: ^dag_surface_primary_expr
) {
ParseSubtreeFound { captured: primary } => optional_present(value: primary)
ParseSubtreeAbsent =>
match body_lower_find_captured(
root: stripped,
emitted: ^dag_surface_postfix_expr
) {
ParseSubtreeFound { captured: postfix } => optional_present(value: postfix)
ParseSubtreeAbsent => optional_absent()
match body_lower_match_spine_right(spine: stripped) {
Absent => optional_absent()
Present { value: after_pattern } =>
match body_lower_match_spine_left(spine: after_pattern) {
Absent => optional_absent()
Present { value: arrow_node } =>
match node_atom_identity_optional(node: body_lower_deep_unwrap_optional(node: arrow_node)) {
Absent => optional_absent()
Present { value: arrow } =>
if arrow == ^dag_token_fat_arrow {
body_lower_match_spine_right(spine: after_pattern)
} else {
optional_absent()
}
}
}
}
Expand Down Expand Up @@ -5582,11 +5589,47 @@ fn body_lower_pattern_lowered(pattern_capture: Node) -> Outcome<Node> {
// its inner match -- and then kept as the FALLBACK for what the value reader declined, where its own
// Absent was reported as match_arm_navigation_refused. That relabel is how an unlowered fn literal in
// an arm body (a fold call's `f: fn(acc, x) { .. }`) surfaced as a navigation failure of the arm.
// An arm body now lowers through body_lower_value_read on both routes -- the pattern-capture route
// and the spine route below -- so its refusal is the value's, located at the value; the navigation
// refusal is left to exactly what it names: an arm whose pattern or `=>` cannot be found.
// An arm body now lowers through body_lower_match_arm_body_lowered on both routes -- the
// pattern-capture route and the spine route below -- which is the value reader for an expression
// body and the statement authority for a statement body, so its refusal is the value's or the
// statement's, located there; the navigation refusal is left to exactly what it names: an arm whose
// pattern or `=>` cannot be found.
// AN ARM BODY THAT IS A STATEMENT SEQUENCE LOWERS THROUGH THE STATEMENT AUTHORITY. The grammar's
// match_arm_stmt_body is seq(stmt, repeat(stmt)) (v2.extdeps.languages.dag
// dag_grammar_match_arm_stmt_body_expr), and the parser realizes it UNWRAPPED:
// v2.compiler.parse parse_match_arm_stmt_body answers the statements' repeat spine itself, with no
// production shell (measured on a parsed arm: `A =>` is followed directly by two `stmt` productions).
// So a statement body is recognized by what it is -- a spine whose head is a `stmt` production and
// which has a successor -- and lowers through body_lower_stmt_spine, the reader a fn body and an if
// arm use: a let binds the rest, the last statement is the value, and any other statement that
// precedes another refuses located. An expression body sits under its own expr production and is
// read by the value reader, as before.
fn body_lower_match_arm_statement_spine_optional(body_capture: Node) -> Optional<Node> {
let spine = body_lower_deep_unwrap_optional(node: body_capture)
match body_lower_stmt_spine_head_optional(spine: spine) {
Absent => optional_absent()
Present { value: head } =>
match parse_production_emitted_identity_optional(node: body_lower_deep_unwrap_optional(node: head)) {
Absent => optional_absent()
Present { value: emitted } =>
if (emitted == ^dag_surface_stmt) && body_lower_stmt_spine_has_successor(spine: spine) {
optional_present(value: spine)
} else {
optional_absent()
}
}
}
}

fn body_lower_match_arm_body_lowered(body_capture: Node) -> Outcome<Node> {
match body_lower_match_arm_statement_spine_optional(body_capture: body_capture) {
Present { value: spine } => body_lower_stmt_spine(spine: spine)
Absent => body_lower_value_read(value: body_capture)
}
}

fn body_lower_match_arm_wire_read(pat_node: Node, body_capture: Node) -> Outcome<Node> {
match body_lower_value_read(value: body_capture) {
match body_lower_match_arm_body_lowered(body_capture: body_capture) {
Rejected { diagnostics: r } => Rejected { diagnostics: r }
Accepted { value: body, diagnostics: d } =>
outcome_with_diagnostics(value: body_lower_match_arm_wire(pat_node: pat_node, body: body), diagnostics: d)
Expand Down Expand Up @@ -7081,45 +7124,6 @@ fn body_lower_match_spine_right(spine: Node) -> Optional<Node> {
}
}

fn body_lower_match_scrutinee_on_token(id: Symbol, left: Node, right: Node) -> Optional<Node> {
match id == ^dag_token_lbrace {
true => Absent
false =>
match id == ^dag_token_kw_match {
true => body_lower_match_scrutinee_from_spine(spine: right)
false =>
match body_lower_operand_ref_optional(node: left) {
Present { value: op } => Present { value: op }
Absent => body_lower_match_scrutinee_from_spine(spine: right)
}
}
}
}

fn body_lower_match_scrutinee_from_spine(spine: Node) -> Optional<Node> {
if is_empty_conj_root(n: spine) {
Absent
} else {
match body_lower_match_spine_left(spine: spine) {
Present { value: left } =>
match body_lower_match_spine_right(spine: spine) {
Present { value: right } =>
match node_atom_identity_optional(node: body_lower_deep_unwrap_optional(node: left)) {
Present { value: id } =>
body_lower_match_scrutinee_on_token(id: id, left: left, right: right)
Absent =>
match body_lower_operand_ref_optional(node: left) {
Present { value: op } => Present { value: op }
Absent => body_lower_match_scrutinee_from_spine(spine: right)
}
}
Absent => Absent
}
Absent => Absent
}
}
}

// THE SCRUTINEE IS A VALUE, READ AS ONE. It was read by the operand reader alone, which before
// gunbc#12145 narrowed a call scrutinee `match nat_compare(a: x, b: y) {..}` to `nat_compare`,
// dropping its arguments, and after it answered Absent, so the whole match refused as
Expand All @@ -7136,18 +7140,38 @@ fn body_lower_match_scrutinee_value(node: Node) -> Outcome<Optional<Node>> {
}
}

// THE SCRUTINEE IS READ FROM ITS GRAMMAR POSITION: match_expr is seq(`match`, seq(binary_expr,
// seq(`{`, ..))), so it is the left of the spine's right, after the `match` keyword. It was found by
// searching the whole match subtree for the first binary_expr, then postfix_expr. On a fn body that
// is the scrutinee, because the parse is unfolded. A data initializer is folded bottom-up before its
// declaration is dispatched (body_lower_data_initializer_body), so its scrutinee's shell is already
// reduced, and the search found the next binary_expr, inside the first arm's body: `data d: Bool =
// match h(a) { X => true .. }` lowered to a match on `true` with `h` and `a` gone and the module
// accepted (gunbc.recurring_failure_mode
// data_initializer_match_reads_its_scrutinee_from_an_arm_at_v2_body_lowering). The position holds on
// both routes, and body_lower_match_scrutinee_value reads an unfolded shell and an already-lowered
// node alike (body_lower_value_lowered peels a lowered node first). A match whose spine is not headed
// by `match` answers Absent, which its caller refuses as match_arm_navigation_refused.
fn body_lower_match_scrutinee_optional(captured: Node) -> Outcome<Optional<Node>> {
match body_lower_find_captured(root: captured, emitted: ^dag_surface_binary_expr) {
ParseSubtreeFound { captured: binary } => body_lower_match_scrutinee_value(node: binary)
ParseSubtreeAbsent =>
match body_lower_find_captured(root: captured, emitted: ^dag_surface_postfix_expr) {
ParseSubtreeFound { captured: postfix } => body_lower_match_scrutinee_value(node: postfix)
ParseSubtreeAbsent =>
outcome_accepted(
value: body_lower_match_scrutinee_from_spine(
spine: body_lower_unwrap_surface_shell(node: captured)
)
)
let spine = body_lower_unwrap_surface_shell(node: captured)
match body_lower_match_spine_left(spine: spine) {
Absent => outcome_accepted(value: optional_absent())
Present { value: head } =>
match node_atom_identity_optional(node: body_lower_deep_unwrap_optional(node: head)) {
Absent => outcome_accepted(value: optional_absent())
Present { value: id } =>
if id == ^dag_token_kw_match {
match body_lower_match_spine_right(spine: spine) {
Absent => outcome_accepted(value: optional_absent())
Present { value: after_keyword } =>
match body_lower_match_spine_left(spine: after_keyword) {
Absent => outcome_accepted(value: optional_absent())
Present { value: scrutinee } => body_lower_match_scrutinee_value(node: scrutinee)
}
}
} else {
outcome_accepted(value: optional_absent())
}
}
}
}
Expand Down
Loading