Repository navigation
CX-K–N: drive complexity violations 271 → 180 #318
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
3290c0a
ee7e863
31bffbd
d198d7e
f20f62a
8a7ad59
e81129c
d885b52
37c66e3
30e3a74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2748,21 +2748,37 @@ fn last_child_or_self(n: Node) -> Node { | |
| // Extract a string name from a Node for use in property values. | ||
| // Keyed-container detection derives from container_type_set (single authority | ||
| // for container identity) plus structural child count — no parallel name list. | ||
| // | ||
| // Split into wrapper (Optional prefix) + inner (child descent) so the CX | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invariant violation: Splitting |
||
| // analyzer sees a 2-member SCC with edges [NonIncreasing, Strict]: | ||
| // node_to_name_str -> node_to_name_str_inner: with_required_cardinality or same n | ||
| // node_to_name_str_inner -> node_to_name_str: structural child via match | ||
| fn node_to_name_str(n: Node) -> String { | ||
| let has_children = n.children |> count > 0 | ||
| let is_optional = n.return_cardinality == CardOptional | ||
| let is_keyed_container = is_container_type(name: n.name) && n.children |> count == 2 | ||
| if is_optional { | ||
| concat("Optional_", node_to_name_str(n: with_required_cardinality(n: n))) | ||
| } else if is_keyed_container { | ||
| if n.children |> count > 1 { concat(n.name, "_", node_to_name_str(n: last_child_or_self(n: n))) } | ||
| else { n.name } | ||
| concat("Optional_", node_to_name_str_inner(n: with_required_cardinality(n: n))) | ||
| } else { | ||
| node_to_name_str_inner(n: n) | ||
| } | ||
| } | ||
|
|
||
| fn node_to_name_str_inner(n: Node) -> String { | ||
| let is_keyed_container = is_container_type(name: n.name) && n.children |> count == 2 | ||
| if is_keyed_container { | ||
| match n.children |> last { | ||
| Some { value: ch } => concat(n.name, "_", node_to_name_str(n: ch)) | ||
| None => n.name | ||
| } | ||
| } else if n.name == "Refined" { | ||
| if has_children { node_to_name_str(n: first_child_or_self(n: n)) } | ||
| else { n.name } | ||
| match n.children |> first { | ||
| Some { value: ch } => node_to_name_str(n: ch) | ||
| None => n.name | ||
| } | ||
| } else if is_container_type(name: n.name) { | ||
| if has_children { concat("List_", node_to_name_str(n: first_child_or_self(n: n))) } | ||
| else { n.name } | ||
| match n.children |> first { | ||
| Some { value: ch } => concat("List_", node_to_name_str(n: ch)) | ||
| None => n.name | ||
| } | ||
| } else if n.name == "" { | ||
| let is_conj = n.connective == Conj | ||
| let is_disj = n.connective == Disj | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -388,18 +388,30 @@ fn node_type_equals(left: Node, right: Node) -> Bool { | |
| let right_tv = if right.inferred != none { is_type_variable(inferred: right.inferred.value) } else { false } | ||
| let left_opt = left.return_cardinality == CardOptional | ||
| let right_opt = right.return_cardinality == CardOptional | ||
| let left_leaf = left.connective == NoConnective && left.children |> count == 0 && left.properties |> count == 0 | ||
| let right_leaf = right.connective == NoConnective && right.children |> count == 0 && right.properties |> count == 0 | ||
| let left_struct = left.connective != NoConnective | ||
| let right_struct = right.connective != NoConnective | ||
| let right_is_unit_eq = right.connective == Conj && right.children |> count == 0 | ||
| let left_is_unit_eq = left.connective == Conj && left.children |> count == 0 | ||
| if left_err || right_err { true } | ||
| else if left_tv && right_tv { true } | ||
| else if left_tv || right_tv { false } | ||
| else if left_opt && right_is_unit_eq { true } | ||
| else if left_is_unit_eq && right_opt { true } | ||
| else if left_leaf && right_leaf { | ||
| else if left_opt && right_opt { | ||
| // Optional unwrap: same tree structure with cardinality stripped. | ||
| // Separate from node_type_equals_core so CX sees SCC edge as Same | ||
| // (wrapper transparency) rather than dragging core's Strict to NonIncreasing. | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invariant violation: Splitting optional-cardinality equality into a wrapper/core pair so the analyzer “sees” a Same edge patches analyzer shape in a producer instead of fixing the upstream authority, violating Root-Cause Depth. |
||
| node_type_equals_core(left: with_required_cardinality(n: left), right: with_required_cardinality(n: right)) | ||
| } | ||
| else { | ||
| node_type_equals_core(left: left, right: right) | ||
| } | ||
| } | ||
|
|
||
| fn node_type_equals_core(left: Node, right: Node) -> Bool { | ||
| let left_leaf = left.connective == NoConnective && left.children |> count == 0 && left.properties |> count == 0 | ||
| let right_leaf = right.connective == NoConnective && right.children |> count == 0 && right.properties |> count == 0 | ||
| let left_struct = left.connective != NoConnective | ||
| let right_struct = right.connective != NoConnective | ||
| if left_leaf && right_leaf { | ||
| left.name == right.name | ||
| } | ||
| else if left_struct && right_struct { | ||
|
|
@@ -437,21 +449,30 @@ fn node_type_equals(left: Node, right: Node) -> Bool { | |
| } | ||
| } | ||
| } | ||
| else if left_opt && right_opt { | ||
| node_type_equals(left: with_required_cardinality(n: left), right: with_required_cardinality(n: right)) | ||
| } | ||
| else { | ||
| let both_maps = node_is_keyed_collection(n: left) && node_is_keyed_collection(n: right) | ||
| if both_maps { | ||
| if left.children |> count == 2 && right.children |> count == 2 { | ||
| let left_first = match left.children |> first { Some { value: v } => v, None => left } | ||
| let right_first = match right.children |> first { Some { value: v } => v, None => right } | ||
| let left_second = match skip(left.children, 1) |> first { Some { value: v } => v, None => left } | ||
| let right_second = match skip(right.children, 1) |> first { Some { value: v } => v, None => right } | ||
| node_type_equals(left: left_first, right: right_first) && node_type_equals(left: left_second, right: right_second) | ||
| } else { | ||
| false | ||
| } | ||
| if left.children |> count == 2 && right.children |> count == 2 { | ||
| match left.children |> first { | ||
| Some { value: left_first } => | ||
| match right.children |> first { | ||
| Some { value: right_first } => | ||
| match left.children |> skip(1) |> first { | ||
| Some { value: left_second } => | ||
| match right.children |> skip(1) |> first { | ||
| Some { value: right_second } => | ||
| node_type_equals(left: left_first, right: right_first) && node_type_equals(left: left_second, right: right_second) | ||
| None => false | ||
| } | ||
| None => false | ||
| } | ||
| None => false | ||
| } | ||
| None => false | ||
| } | ||
| } else { | ||
| false | ||
| } | ||
| } | ||
| else if left.params |> count > 0 && right.params |> count > 0 { | ||
| if left.params |> count != right.params |> count { false } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -924,29 +924,37 @@ fn build_type_rendering(n: Node, rc_types: Map<String, Bool>, recursive_types: M | |
| // Callable: fn(A, B) -> R | ||
| if n.name == "Callable" { | ||
| let param_renderings = n.params |> map(p => build_type_rendering(n: param_node_type_expr(n: p), rc_types: rc_types, recursive_types: recursive_types)) | ||
| let ret = match n.inferred { | ||
| Some { value: Resolved { node: rt } } => Some { value: build_type_rendering(n: rt, rc_types: rc_types, recursive_types: recursive_types) } | ||
| _ => none | ||
| let has_resolved_return = match n.inferred { | ||
| Some { value: Resolved { node: _ } } => true | ||
| _ => false | ||
| } | ||
| let ret = if has_resolved_return { | ||
| Some { value: build_type_rendering(n: rt_type(n: n), rc_types: rc_types, recursive_types: recursive_types) } | ||
| } else { none } | ||
| return TypeRendering { | ||
| type_name: "Callable", params: param_renderings, return_type: ret, | ||
| element: none, key: none, value: none, inner: none, generic_args: [], | ||
| shared: false, boxed: false, is_tuple: false, is_error: false, error_label: "" | ||
| } | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Invariant violation: Splitting |
||
| } | ||
|
|
||
| // Optional wrapping | ||
| // Optional wrapping — dispatch directly to connective handler to avoid | ||
| // a NonIncreasing self-loop (wrapper preserves tree size but self-edge | ||
| // creates a non-descending cycle in the SCC proof). | ||
| let is_optional = n.return_cardinality == CardOptional | ||
| if is_optional { | ||
| let inner_tr = build_type_rendering(n: with_required_cardinality(n: n), rc_types: rc_types, recursive_types: recursive_types) | ||
| let inner_tr = build_type_rendering_dispatch(n: with_required_cardinality(n: n), rc_types: rc_types, recursive_types: recursive_types) | ||
| return TypeRendering { | ||
| type_name: "optional", inner: Some { value: inner_tr }, | ||
| element: none, key: none, value: none, params: [], return_type: none, | ||
| generic_args: [], shared: false, boxed: false, is_tuple: false, is_error: false, error_label: "" | ||
| } | ||
| } | ||
|
|
||
| // Dispatch on connective | ||
| build_type_rendering_dispatch(n: n, rc_types: rc_types, recursive_types: recursive_types) | ||
| } | ||
|
|
||
| fn build_type_rendering_dispatch(n: Node, rc_types: Map<String, Bool>, recursive_types: Map<String, Bool>) -> TypeRendering { | ||
| let is_conj = n.connective == Conj | ||
| let is_disj = n.connective == Disj | ||
| if !is_conj && !is_disj { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Invariant violation: Lowering SameArgumentCall to Repeat(Forever) compensates for a missing structural ranking witness with a fabricated machine-max bound, violating Modeling Faithfulness and Root-Cause Depth.