Skip to content
Closed
29 changes: 28 additions & 1 deletion src/v1/04_infer.dag
Original file line number Diff line number Diff line change
Expand Up @@ -13042,6 +13042,31 @@ fn rewire_str_binding_overlay(str_bindings: Map<String, TypeBinding>, rewrites:
)
}

// THE KERNEL LAYER IS NOT AN IMPORT IDENTITY TO CANONICALIZE (2026-08-31, frontier receipt 1
// follow-up). This rewire replaces an inherited binding with the corpus-wide canonical EXPORTED
// declaration when exactly one module exports the name. A KERNEL binding in ancestry is not an
// inherited import identity: it is the precedence layer build_ancestry_precedence installed ABOVE
// the import union (locals > kernel > direct-selected > union), and String has exactly one
// corpus exporter (v2.std.text), so the unguarded rewrite substituted the structural declaration
// for the kernel identity in every module's persisted env -- inference (pre-rewire) answered
// kernel while emit (post-rewire) read the substituted authority, the divergence behind the
// pub-use String shadow measured as 139 of receipt 1's 146 E0308 rows. The guard is keyed on the
// BINDING'S OWN identity (the kernel span file), never on a name roster: a module that locally
// declares or genuinely imports a kernel-spelled name keeps its ordinary rewire, because its
// binding does not carry the kernel span. The confirming discriminator was measured before the
// fix: v2.std.compilers.target_model imports v2.std.text in TWO import statements, so its
// direct-exporter count for String is 2, the rewrite skipped it, and it was the one module whose
// emit-time lookup still answered kernel.
fn ancestry_binding_is_kernel_identity(bindings: Map<String, TypeBinding>, name: String) -> Bool {
match map_get(bindings, name) {
Absent => false
Present { value: binding } => match binding.resolved.ident_span {
Present { value: sp } => sp.file == concat("<kernel:", concat(name, ">"))
Absent => false
}
}
}

fn rewire_type_env_import_str_binding_identity(modules: List<TypedModule>, source_indices: Map<String, NewlineIndex>) -> List<TypedModule> {
let export_indexes = build_export_indexes(modules: modules, source_indices: source_indices)
let type_name_index = export_indexes.by_name
Expand All @@ -13053,7 +13078,9 @@ fn rewire_type_env_import_str_binding_identity(modules: List<TypedModule>, sourc
}
let import_export_names = direct_import_export_name_sets(m: m, export_name_index: export_name_index, source_indices: source_indices)
let exporter_counts = direct_import_exporter_counts(import_export_names: import_export_names)
let ancestry_keys = m.type_env.ancestry_str_bindings |> map_keys
let ancestry_keys = m.type_env.ancestry_str_bindings
|> map_keys
|> filter(name => !ancestry_binding_is_kernel_identity(bindings: m.type_env.ancestry_str_bindings, name: name))
let str_keys = m.type_env.str_bindings |> map_keys
let inherited_keys = concat(ancestry_keys, str_keys)
let rewrites = rewire_canonical_rewrites(
Expand Down
177 changes: 158 additions & 19 deletions src/v1/05_emit_rust.dag

Large diffs are not rendered by default.

151 changes: 150 additions & 1 deletion src/v1/compiler_tests_rust.dag
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,156 @@ fn ct_coercion_tests() -> String {
test_fns |> join(separator: "\n"),
ct_rust_btree_set_ord_eligibility_test(),
ct_diagnostics_carrier_grounding_test(),
ct_render_rust_applied_type_qualified_base_test())
ct_render_rust_applied_type_qualified_base_test(),
ct_generic_param_declines_fail_closed_unwrap_test(),
ct_witness_carrier_declines_non_witness_expected_type_test())
}

// THE ENROLLED RED FOR `rust_call_arg_fail_closed_unwrap`, and the control that keeps the repair
// from being a blanket disable. Arm 1 is the discriminating one: a callee whose parameter type is
// its own type VARIABLE cannot say whether the instantiated parameter is optional, so no unwrap may
// be injected -- it is that injection that emitted
// `outcome_accepted(Some(child).expect("fail-closed: ..."))` in v2.compiler.target_carriers, where
// the instantiated parameter is `Optional<Node>` and the unwrap strips exactly the Option the
// return type demands. Arm 2 holds the other direction: a CONCRETE non-optional parameter still
// takes the unwrap, so a repair that simply stopped injecting would go red here.
fn ct_generic_param_declines_fail_closed_unwrap_test() -> String {
concat(
" fn optional_typed_arg_node() -> std::rc::Rc<crate::v1_std_core::Node> {\n",
" let optional_type = shaped_type_node(\"Node\", Vec::new());\n",
" let optional_type = std::rc::Rc::new(crate::v1_std_core::Node {\n",
" return_cardinality: crate::v1_std_core::Cardinality::CardOptional,\n",
" ..(*optional_type).clone()\n",
" });\n",
" let arg = named_type_node(\"child\");\n",
" std::rc::Rc::new(crate::v1_std_core::Node {\n",
" inferred: Some(std::rc::Rc::new(crate::v1_std_core::InferredNode::Resolved {\n",
" node: optional_type,\n",
" })),\n",
" ..(*arg).clone()\n",
" })\n",
" }\n\n",
" fn callee_with_one_param(param_type_name: &str) -> Option<std::rc::Rc<crate::v1_compiler_infer_items::ItemInfo>> {\n",
" let param = shaped_type_node(\"value\", vec![named_type_node(param_type_name)]);\n",
" Some(std::rc::Rc::new(crate::v1_compiler_infer_items::ItemInfo {\n",
" name: \"outcome_accepted\".to_string(),\n",
" module_name: \"v2.std.diagnostic\".to_string(),\n",
" kind: crate::v1_compiler_infer_items::ItemKind::FnItem,\n",
" service_names: std::rc::Rc::new(im::Vector::new()),\n",
" resource_names: std::rc::Rc::new(im::Vector::new()),\n",
" params: std::rc::Rc::new(vec![param].into()),\n",
" is_self_recursive: false,\n",
" has_non_tail_self_call: false,\n",
" }))\n",
" }\n\n",
" #[test]\n",
" fn generic_parameter_declines_the_fail_closed_unwrap() {\n",
" let source_indices = std::rc::Rc::new(HashMap::new());\n",
" let arg = optional_typed_arg_node();\n",
" let generic = crate::v1_compiler_emit_rust::rust_call_arg_fail_closed_unwrap(\n",
" \"child.clone()\".to_string(),\n",
" arg.clone(),\n",
" callee_with_one_param(\"T\"),\n",
" 0,\n",
" \"outcome_accepted\".to_string(),\n",
" source_indices.clone(),\n",
" );\n",
" assert_eq!(\n",
" generic, \"child.clone()\",\n",
" \"a type-variable parameter cannot say the instantiation is non-optional, so no unwrap may be injected\"\n",
" );\n",
" let concrete = crate::v1_compiler_emit_rust::rust_call_arg_fail_closed_unwrap(\n",
" \"child.clone()\".to_string(),\n",
" arg,\n",
" callee_with_one_param(\"Node\"),\n",
" 0,\n",
" \"node_locus\".to_string(),\n",
" source_indices,\n",
" );\n",
" assert!(\n",
" concrete.contains(\".expect(\"),\n",
" \"a concrete non-optional parameter must still take the unwrap: {}\",\n",
" concrete\n",
" );\n",
" }\n\n")
}

// THE ENROLLED RED FOR THE WITNESS CARRIER'S EXPECTED-TYPE SOURCE, with its control. Arm 1 is
// discriminating: `Outcome<Witness<Node>>` is the type expected of the whole expression at a bare
// `Violates` inside `outcome_with_diagnostics(value: Violates { .. }, ..)`, and it says nothing
// about the witness carrier -- reading it as one emitted
// `Witness::<Rc<Outcome<Rc<Witness<Rc<Node>>>>>>::Violates` in v2.compiler.compile. Arm 2 keeps the
// source alive for the case it can answer: a `Witness<Node>` expected type still yields `Node`.
fn ct_witness_carrier_declines_non_witness_expected_type_test() -> String {
concat(
" #[test]\n",
" fn witness_carrier_declines_a_non_witness_expected_type() {\n",
" let source_indices = std::rc::Rc::new(HashMap::new());\n",
" let shared = std::rc::Rc::new(im::OrdSet::new());\n",
" let shared2 = shared.clone();\n",
" let source_indices2 = source_indices.clone();\n",
" let empty_emit = crate::v1_compiler_infer_emit_info::empty_emit_graph_info();\n",
" let witness_of_node = shaped_type_node(\"Witness\", vec![named_type_node(\"Node\")]);\n",
" let outcome_of_witness = shaped_type_node(\"Outcome\", vec![witness_of_node.clone()]);\n",
" let emit_with_outcome = std::rc::Rc::new(crate::v1_compiler_infer_emit_info::EmitGraphInfo {\n",
" expected_type: Some(outcome_of_witness),\n",
" ..(*empty_emit).clone()\n",
" });\n",
" assert!(\n",
" crate::v1_compiler_emit_rust::rust_witness_type_arg_from_expected_type(\n",
" emit_with_outcome,\n",
" shared.clone(),\n",
" source_indices.clone()\n",
" )\n",
" .is_none(),\n",
" \"an expected type whose head is not Witness is not evidence about a witness carrier\"\n",
" );\n",
" let emit_with_witness = std::rc::Rc::new(crate::v1_compiler_infer_emit_info::EmitGraphInfo {\n",
" expected_type: Some(witness_of_node),\n",
" ..(*empty_emit).clone()\n",
" });\n",
" assert_eq!(\n",
" crate::v1_compiler_emit_rust::rust_witness_type_arg_from_expected_type(\n",
" emit_with_witness,\n",
" shared,\n",
" source_indices\n",
" ),\n",
" Some(\"Node\".to_string()),\n",
" \"a Witness-headed expected type still answers with its carrier\"\n",
" );\n",
" let no_fields: Vec<std::rc::Rc<crate::v1_std_core::Node>> = Vec::new();\n",
" let mut variants = HashMap::new();\n",
" variants.insert(\"Holds\".to_string(), \"Witness\".to_string());\n",
" variants.insert(\"Violates\".to_string(), \"Witness\".to_string());\n",
" let emit_with_variants = std::rc::Rc::new(crate::v1_compiler_infer_emit_info::EmitGraphInfo {\n",
" variant_to_enum: std::rc::Rc::new(variants),\n",
" ..(*empty_emit).clone()\n",
" });\n",
" assert!(\n",
" crate::v1_compiler_emit_rust::rust_witness_type_arg_for_variant(\n",
" \"Violates\".to_string(),\n",
" shaped_type_node(\"Witness\", vec![named_type_node(\"Holds\")]),\n",
" std::rc::Rc::new(no_fields.clone().into()),\n",
" shared2.clone(),\n",
" emit_with_variants.clone(),\n",
" source_indices2.clone()\n",
" )\n",
" .is_none(),\n",
" \"the Violates fallback must decline a non-Witness resolved type too, or the fabrication only moves one frame down\"\n",
" );\n",
" assert_eq!(\n",
" crate::v1_compiler_emit_rust::rust_witness_type_arg_for_variant(\n",
" \"Violates\".to_string(),\n",
" shaped_type_node(\"Witness\", vec![named_type_node(\"Node\")]),\n",
" std::rc::Rc::new(no_fields.into()),\n",
" shared2,\n",
" empty_emit,\n",
" source_indices2\n",
" ),\n",
" Some(\"Node\".to_string()),\n",
" \"a Witness-headed resolved type still answers the Violates fallback\"\n",
" );\n",
" }\n\n")
}

fn ct_render_rust_applied_type_qualified_base_test() -> String {
Expand Down
136 changes: 136 additions & 0 deletions src/v1/stage0/src/compiler_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2346,6 +2346,142 @@ mod compiler_tests {
assert_eq!(rendered, "Vec<i64>");
}

fn optional_typed_arg_node() -> std::rc::Rc<crate::v1_std_core::Node> {
let optional_type = shaped_type_node("Node", Vec::new());
let optional_type = std::rc::Rc::new(crate::v1_std_core::Node {
return_cardinality: crate::v1_std_core::Cardinality::CardOptional,
..(*optional_type).clone()
});
let arg = named_type_node("child");
std::rc::Rc::new(crate::v1_std_core::Node {
inferred: Some(std::rc::Rc::new(
crate::v1_std_core::InferredNode::Resolved {
node: optional_type,
},
)),
..(*arg).clone()
})
}

fn callee_with_one_param(
param_type_name: &str,
) -> Option<std::rc::Rc<crate::v1_compiler_infer_items::ItemInfo>> {
let param = shaped_type_node("value", vec![named_type_node(param_type_name)]);
Some(std::rc::Rc::new(crate::v1_compiler_infer_items::ItemInfo {
name: "outcome_accepted".to_string(),
module_name: "v2.std.diagnostic".to_string(),
kind: crate::v1_compiler_infer_items::ItemKind::FnItem,
service_names: std::rc::Rc::new(im::Vector::new()),
resource_names: std::rc::Rc::new(im::Vector::new()),
params: std::rc::Rc::new(vec![param].into()),
is_self_recursive: false,
has_non_tail_self_call: false,
}))
}

#[test]
fn generic_parameter_declines_the_fail_closed_unwrap() {
let source_indices = std::rc::Rc::new(HashMap::new());
let arg = optional_typed_arg_node();
let generic = crate::v1_compiler_emit_rust::rust_call_arg_fail_closed_unwrap(
"child.clone()".to_string(),
arg.clone(),
callee_with_one_param("T"),
0,
"outcome_accepted".to_string(),
source_indices.clone(),
);
assert_eq!(
generic, "child.clone()",
"a type-variable parameter cannot say the instantiation is non-optional, so no unwrap may be injected"
);
let concrete = crate::v1_compiler_emit_rust::rust_call_arg_fail_closed_unwrap(
"child.clone()".to_string(),
arg,
callee_with_one_param("Node"),
0,
"node_locus".to_string(),
source_indices,
);
assert!(
concrete.contains(".expect("),
"a concrete non-optional parameter must still take the unwrap: {}",
concrete
);
}

#[test]
fn witness_carrier_declines_a_non_witness_expected_type() {
let source_indices = std::rc::Rc::new(HashMap::new());
let shared = std::rc::Rc::new(im::OrdSet::new());
let shared2 = shared.clone();
let source_indices2 = source_indices.clone();
let empty_emit = crate::v1_compiler_infer_emit_info::empty_emit_graph_info();
let witness_of_node = shaped_type_node("Witness", vec![named_type_node("Node")]);
let outcome_of_witness = shaped_type_node("Outcome", vec![witness_of_node.clone()]);
let emit_with_outcome =
std::rc::Rc::new(crate::v1_compiler_infer_emit_info::EmitGraphInfo {
expected_type: Some(outcome_of_witness),
..(*empty_emit).clone()
});
assert!(
crate::v1_compiler_emit_rust::rust_witness_type_arg_from_expected_type(
emit_with_outcome,
shared.clone(),
source_indices.clone()
)
.is_none(),
"an expected type whose head is not Witness is not evidence about a witness carrier"
);
let emit_with_witness =
std::rc::Rc::new(crate::v1_compiler_infer_emit_info::EmitGraphInfo {
expected_type: Some(witness_of_node),
..(*empty_emit).clone()
});
assert_eq!(
crate::v1_compiler_emit_rust::rust_witness_type_arg_from_expected_type(
emit_with_witness,
shared,
source_indices
),
Some("Node".to_string()),
"a Witness-headed expected type still answers with its carrier"
);
let no_fields: Vec<std::rc::Rc<crate::v1_std_core::Node>> = Vec::new();
let mut variants = HashMap::new();
variants.insert("Holds".to_string(), "Witness".to_string());
variants.insert("Violates".to_string(), "Witness".to_string());
let emit_with_variants =
std::rc::Rc::new(crate::v1_compiler_infer_emit_info::EmitGraphInfo {
variant_to_enum: std::rc::Rc::new(variants),
..(*empty_emit).clone()
});
assert!(
crate::v1_compiler_emit_rust::rust_witness_type_arg_for_variant(
"Violates".to_string(),
shaped_type_node("Witness", vec![named_type_node("Holds")]),
std::rc::Rc::new(no_fields.clone().into()),
shared2.clone(),
emit_with_variants.clone(),
source_indices2.clone()
)
.is_none(),
"the Violates fallback must decline a non-Witness resolved type too, or the fabrication only moves one frame down"
);
assert_eq!(
crate::v1_compiler_emit_rust::rust_witness_type_arg_for_variant(
"Violates".to_string(),
shaped_type_node("Witness", vec![named_type_node("Node")]),
std::rc::Rc::new(no_fields.into()),
shared2,
empty_emit,
source_indices2
),
Some("Node".to_string()),
"a Witness-headed resolved type still answers the Violates fallback"
);
}

/// Return current process RSS in bytes (macOS via mach_task_basic_info).
fn get_rss_bytes() -> u64 {
#[cfg(target_os = "macos")]
Expand Down
Loading
Loading