From af272c2d579c40c881a779ed528ddad8350fcd33 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:29:14 +0000 Subject: [PATCH 01/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/05_emit_rust.dag | 4 +-- src/v2/stage0/src/v2_compiler_emit_rust.rs | 4 +-- src/v2/tests/src/pipeline.rs | 30 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/v2/05_emit_rust.dag b/src/v2/05_emit_rust.dag index fcbebcf007f..4c1c64b58cd 100644 --- a/src/v2/05_emit_rust.dag +++ b/src/v2/05_emit_rust.dag @@ -5851,7 +5851,7 @@ fn data_value_has_cross_refs(value: Node) -> Bool { } 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 raw_ty_str = render_rust_type(n: type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices) + let raw_ty_str = render_rust_type_with_applied_binding(n: type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices) let ty_str = if raw_ty_str == "BoundedLattice" || raw_ty_str == "Rc" { match field_value_by_name(record: value, field_name: "top", source_indices: scope.type_env.source_indices) { Some { value: top_value } => @@ -5907,7 +5907,7 @@ fn rust_nominal_identity_data_expr(type_node: Node, value: Node, source_indices: } 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) + let raw_ty_str = render_rust_type_with_applied_binding(n: type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices) let type_name = authored_name_at(source_indices: scope.type_env.source_indices, node: type_node) if type_name == "BoundedLattice" { match value.expr_data { diff --git a/src/v2/stage0/src/v2_compiler_emit_rust.rs b/src/v2/stage0/src/v2_compiler_emit_rust.rs index 7920c6b191d..b043bbb3e5f 100644 --- a/src/v2/stage0/src/v2_compiler_emit_rust.rs +++ b/src/v2/stage0/src/v2_compiler_emit_rust.rs @@ -16235,7 +16235,7 @@ pub fn emit_data_def( emit_info: Rc, ) -> String { { - let raw_ty_str = render_rust_type( + let raw_ty_str = render_rust_type_with_applied_binding( type_node.clone(), shared_types.clone(), scope.type_env.clone().source_indices.clone(), @@ -16403,7 +16403,7 @@ pub fn emit_data_def_body( needs_rc: bool, ) -> String { { - let raw_ty_str = render_rust_type( + let raw_ty_str = render_rust_type_with_applied_binding( type_node.clone(), shared_types.clone(), scope.type_env.clone().source_indices.clone(), diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index 3a6e08aa658..7359653b969 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5215,6 +5215,36 @@ type Outer { ); } +#[test] +fn generic_data_annotation_preserves_type_args() { + let source = r#" +module test_generic_data_annotation + +type Pair { + first: A + second: B +} + +data sample_pair: Pair = Pair { + first: 1 + second: "ok" +} +"#; + let result = compile_dag(source); + assert_no_diagnostics(&result); + let content = find_file(&result, "src/test_generic_data_annotation.rs"); + assert!( + content.contains("pub fn sample_pair() -> Pair"), + "generic data return type should preserve applied type args, got:\n{}", + content + ); + assert!( + !content.contains("pub fn sample_pair() -> Pair {"), + "generic data return type must not emit bare Pair, got:\n{}", + content + ); +} + // ── Targeted type rendering correctness tests ───────────────────────── fn test_leaf_node(name: &str) -> Rc { From 896bce458b867bbc9bbee66551b8ec89ef0ab88e Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:34:57 +0000 Subject: [PATCH 02/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/04_resolve.dag | 14 ++- .../stage0/src/v2_compiler_infer_resolve.rs | 86 ++++++++++++++++++- 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/src/v2/04_resolve.dag b/src/v2/04_resolve.dag index 6223cc075bf..f7d9f5bc0a6 100644 --- a/src/v2/04_resolve.dag +++ b/src/v2/04_resolve.dag @@ -899,7 +899,19 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemResu } else { resolve_node(n: item.type_annotation.value, env: env, module_name: module_name) } - let resolved_anno = if item.type_annotation == none { none } else { Some { value: anno_resolved.resolved } } + let resolved_anno = if item.type_annotation == none { none } else { + let authored_anno = item.type_annotation.value + let has_applied_binding = find_property(props: anno_resolved.resolved.properties, prop_name: "__applied_type_args", source_indices: env.source_indices) != none + if authored_anno.children |> count > 0 && !has_applied_binding { + let arg_results = authored_anno.children |> map(child => resolve_node(n: child, env: env, module_name: module_name)) + let resolved_args = arg_results |> map(ar => ar.resolved) + let applied_type_args = Node { name: authored_name(env: env, node: authored_anno), span: authored_anno.span, ident_span: authored_anno.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: none, return_cardinality: authored_anno.return_cardinality, uses: [], body: none, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } + let applied_type_args_property = make_field_init_node(name: "__applied_type_args", value: applied_type_args, span: authored_anno.span, name_span: authored_anno.span) + Some { value: Node { name: anno_resolved.resolved.name, span: anno_resolved.resolved.span, ident_span: anno_resolved.resolved.ident_span, children: anno_resolved.resolved.children, connective: anno_resolved.resolved.connective, params: anno_resolved.resolved.params, inferred: anno_resolved.resolved.inferred, return_cardinality: anno_resolved.resolved.return_cardinality, uses: anno_resolved.resolved.uses, body: anno_resolved.resolved.body, transport: anno_resolved.resolved.transport, properties: concat(anno_resolved.resolved.properties, [applied_type_args_property]), type_annotation: anno_resolved.resolved.type_annotation, is_self_recursive: anno_resolved.resolved.is_self_recursive, has_non_tail_self_call: anno_resolved.resolved.has_non_tail_self_call, match_pattern: anno_resolved.resolved.match_pattern, expr_data: anno_resolved.resolved.expr_data } } + } else { + Some { value: anno_resolved.resolved } + } + } let anno_diags = anno_resolved.diagnostics let transport_resolved = if item.transport == none { diff --git a/src/v2/stage0/src/v2_compiler_infer_resolve.rs b/src/v2/stage0/src/v2_compiler_infer_resolve.rs index bf7a79479df..6b49fa8900a 100644 --- a/src/v2/stage0/src/v2_compiler_infer_resolve.rs +++ b/src/v2/stage0/src/v2_compiler_infer_resolve.rs @@ -29,7 +29,7 @@ pub use crate::v2_std_core::{ arg_name_at, arg_value, arm_body, arm_guard, arm_pattern, authored_name_at, default_ident_span, expr_call_func_at, expr_method_name_at, field_init_node_name_at, field_init_node_value, field_node_cardinality, field_node_default_value, field_node_from_key, field_node_name_at, - field_node_type_expr, foreach_variable_at, generic_param_name_at, intern, is_compiler_error, + field_node_type_expr, find_property, foreach_variable_at, generic_param_name_at, intern, is_compiler_error, is_container_type, is_kernel_type, is_local_transport, kernel_span, let_binding_name_at, local_transport_node, make_arg_node, make_arm_node, make_error_node, make_expr_error_node, make_expr_node, make_field_init_node, make_field_node, make_interp_part_node, @@ -2775,7 +2775,89 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) let resolved_anno = if (item.type_annotation.clone() == None) { None } else { - Some(anno_resolved.resolved.clone()) + { + let authored_anno = item.type_annotation.clone().unwrap(); + let has_applied_binding = (find_property( + anno_resolved.resolved.clone().properties.clone(), + "__applied_type_args".to_string(), + env.source_indices.clone(), + ) != None); + if (((authored_anno.children.clone().len() as i64) > 0) && !has_applied_binding) { + let arg_results = Rc::new({ + let mut __result = Vec::new(); + for child in authored_anno.children.clone().iter().cloned() { + __result.push(resolve_node( + child.clone(), + env.clone(), + module_name.clone(), + )); + } + __result + }); + let resolved_args = Rc::new({ + let mut __result = Vec::new(); + for ar in arg_results.clone().iter().cloned() { + __result.push(ar.resolved.clone()); + } + __result + }); + let applied_type_args = Rc::new(Node { + name: authored_name(env.clone(), authored_anno.clone()), + span: authored_anno.span.clone(), + ident_span: authored_anno.ident_span.clone(), + children: resolved_args, + connective: Connective::NoConnective, + params: Rc::new(vec![]), + inferred: None, + return_cardinality: authored_anno.return_cardinality.clone(), + uses: Rc::new(vec![]), + body: None, + transport: None, + properties: Rc::new(vec![]), + type_annotation: None, + is_self_recursive: false, + has_non_tail_self_call: false, + match_pattern: None, + expr_data: Rc::new(ExprData::NoExprData), + ident: None, + }); + let applied_type_args_property = make_field_init_node( + "__applied_type_args".to_string(), + applied_type_args, + authored_anno.span.clone(), + authored_anno.span.clone(), + ); + Some(Rc::new(Node { + name: anno_resolved.resolved.clone().name.clone(), + span: anno_resolved.resolved.clone().span.clone(), + ident_span: anno_resolved.resolved.clone().ident_span.clone(), + children: anno_resolved.resolved.clone().children.clone(), + connective: anno_resolved.resolved.clone().connective.clone(), + params: anno_resolved.resolved.clone().params.clone(), + inferred: anno_resolved.resolved.clone().inferred.clone(), + return_cardinality: anno_resolved.resolved.clone().return_cardinality.clone(), + uses: anno_resolved.resolved.clone().uses.clone(), + body: anno_resolved.resolved.clone().body.clone(), + transport: anno_resolved.resolved.clone().transport.clone(), + properties: v2_rt::concat( + anno_resolved.resolved.clone().properties.clone(), + Rc::new(vec![applied_type_args_property]), + ), + type_annotation: anno_resolved.resolved.clone().type_annotation.clone(), + is_self_recursive: anno_resolved.resolved.clone().is_self_recursive, + has_non_tail_self_call: anno_resolved + .resolved + .clone() + .has_non_tail_self_call + .clone(), + match_pattern: anno_resolved.resolved.clone().match_pattern.clone(), + expr_data: anno_resolved.resolved.clone().expr_data.clone(), + ident: None, + })) + } else { + Some(anno_resolved.resolved.clone()) + } + } }; let anno_diags = anno_resolved.diagnostics.clone(); let transport_resolved = if (item.transport.clone() == None) { From 1b083920043a5ff5a1ac0cdab637c6ceca14f9eb Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:36:31 +0000 Subject: [PATCH 03/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/05_emit_rust.dag | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/v2/05_emit_rust.dag b/src/v2/05_emit_rust.dag index 4c1c64b58cd..bf11d433050 100644 --- a/src/v2/05_emit_rust.dag +++ b/src/v2/05_emit_rust.dag @@ -1656,7 +1656,20 @@ fn render_rust_type_with_applied_binding(n: Node, shared_types: Set, sou } else { render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) } - None => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) + None => + match n.inferred { + Some { value: Resolved { node: resolved } } => + match find_property(props: resolved.properties, prop_name: "__applied_type_args", source_indices: source_indices) { + Some { value: applied } => + if applied.children |> count > 0 { + render_rust_applied_type(n: applied, shared_types: shared_types, source_indices: source_indices) + } else { + render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) + } + None => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) + } + _ => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) + } } } From 486d46922e75ec7fcd6d81dcd0007d26d5a3b66f Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:38:03 +0000 Subject: [PATCH 04/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/stage0/src/v2_compiler_emit_rust.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/v2/stage0/src/v2_compiler_emit_rust.rs b/src/v2/stage0/src/v2_compiler_emit_rust.rs index b043bbb3e5f..ecc62d99e69 100644 --- a/src/v2/stage0/src/v2_compiler_emit_rust.rs +++ b/src/v2/stage0/src/v2_compiler_emit_rust.rs @@ -3478,7 +3478,23 @@ pub fn render_rust_type_with_applied_binding( render_rust_type(n.clone(), shared_types, source_indices.clone()) } } - None => render_rust_type(n.clone(), shared_types, source_indices.clone()), + None => match n.inferred.clone().as_deref().cloned() { + Some(Resolved { node: resolved, .. }) => match find_property( + resolved.properties.clone(), + "__applied_type_args".to_string(), + source_indices.clone(), + ) { + Some(applied) => { + if ((applied.children.clone().len() as i64) > 0) { + render_rust_applied_type(applied.clone(), shared_types, source_indices.clone()) + } else { + render_rust_type(n.clone(), shared_types, source_indices.clone()) + } + } + None => render_rust_type(n.clone(), shared_types, source_indices.clone()), + }, + _ => render_rust_type(n.clone(), shared_types, source_indices.clone()), + }, } } From 5b6c5f55d657de80b967c38cde39b0d678b088bd Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:39:36 +0000 Subject: [PATCH 05/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/tests/src/pipeline.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index 7359653b969..60136381a5d 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5233,6 +5233,11 @@ data sample_pair: Pair = Pair { let result = compile_dag(source); assert_no_diagnostics(&result); let content = find_file(&result, "src/test_generic_data_annotation.rs"); + let parsed = parse_source(source); + let module = parsed.module.as_ref().expect("module"); + let item = module.children.iter().find(|i| i.name == "sample_pair").expect("sample_pair"); + let ann = item.type_annotation.as_ref().expect("annotation"); + eprintln!("annotation children: {} inferred: {:?} props: {}", ann.children.len(), ann.inferred, ann.properties.len()); assert!( content.contains("pub fn sample_pair() -> Pair"), "generic data return type should preserve applied type args, got:\n{}", From 177123cf2108bd345fd6ef686aacd17dde3730e5 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:42:33 +0000 Subject: [PATCH 06/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/04_resolve.dag | 2 +- .../stage0/src/v2_compiler_infer_resolve.rs | 38 +++++++++---------- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/v2/04_resolve.dag b/src/v2/04_resolve.dag index f7d9f5bc0a6..d5c72dd805d 100644 --- a/src/v2/04_resolve.dag +++ b/src/v2/04_resolve.dag @@ -907,7 +907,7 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemResu let resolved_args = arg_results |> map(ar => ar.resolved) let applied_type_args = Node { name: authored_name(env: env, node: authored_anno), span: authored_anno.span, ident_span: authored_anno.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: none, return_cardinality: authored_anno.return_cardinality, uses: [], body: none, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } let applied_type_args_property = make_field_init_node(name: "__applied_type_args", value: applied_type_args, span: authored_anno.span, name_span: authored_anno.span) - Some { value: Node { name: anno_resolved.resolved.name, span: anno_resolved.resolved.span, ident_span: anno_resolved.resolved.ident_span, children: anno_resolved.resolved.children, connective: anno_resolved.resolved.connective, params: anno_resolved.resolved.params, inferred: anno_resolved.resolved.inferred, return_cardinality: anno_resolved.resolved.return_cardinality, uses: anno_resolved.resolved.uses, body: anno_resolved.resolved.body, transport: anno_resolved.resolved.transport, properties: concat(anno_resolved.resolved.properties, [applied_type_args_property]), type_annotation: anno_resolved.resolved.type_annotation, is_self_recursive: anno_resolved.resolved.is_self_recursive, has_non_tail_self_call: anno_resolved.resolved.has_non_tail_self_call, match_pattern: anno_resolved.resolved.match_pattern, expr_data: anno_resolved.resolved.expr_data } } + Some { value: Node { name: authored_anno.name, span: authored_anno.span, ident_span: authored_anno.ident_span, children: authored_anno.children, connective: authored_anno.connective, params: authored_anno.params, inferred: Some { value: Resolved { node: anno_resolved.resolved } }, return_cardinality: authored_anno.return_cardinality, uses: authored_anno.uses, body: authored_anno.body, transport: authored_anno.transport, properties: concat(anno_resolved.resolved.properties, [applied_type_args_property]), type_annotation: authored_anno.type_annotation, is_self_recursive: authored_anno.is_self_recursive, has_non_tail_self_call: authored_anno.has_non_tail_self_call, match_pattern: authored_anno.match_pattern, expr_data: authored_anno.expr_data } } } else { Some { value: anno_resolved.resolved } } diff --git a/src/v2/stage0/src/v2_compiler_infer_resolve.rs b/src/v2/stage0/src/v2_compiler_infer_resolve.rs index 6b49fa8900a..8d3b8494525 100644 --- a/src/v2/stage0/src/v2_compiler_infer_resolve.rs +++ b/src/v2/stage0/src/v2_compiler_infer_resolve.rs @@ -2828,30 +2828,28 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) authored_anno.span.clone(), ); Some(Rc::new(Node { - name: anno_resolved.resolved.clone().name.clone(), - span: anno_resolved.resolved.clone().span.clone(), - ident_span: anno_resolved.resolved.clone().ident_span.clone(), - children: anno_resolved.resolved.clone().children.clone(), - connective: anno_resolved.resolved.clone().connective.clone(), - params: anno_resolved.resolved.clone().params.clone(), - inferred: anno_resolved.resolved.clone().inferred.clone(), - return_cardinality: anno_resolved.resolved.clone().return_cardinality.clone(), - uses: anno_resolved.resolved.clone().uses.clone(), - body: anno_resolved.resolved.clone().body.clone(), - transport: anno_resolved.resolved.clone().transport.clone(), + name: authored_anno.name.clone(), + span: authored_anno.span.clone(), + ident_span: authored_anno.ident_span.clone(), + children: authored_anno.children.clone(), + connective: authored_anno.connective.clone(), + params: authored_anno.params.clone(), + inferred: Some(Rc::new(Resolved { + node: anno_resolved.resolved.clone(), + })), + return_cardinality: authored_anno.return_cardinality.clone(), + uses: authored_anno.uses.clone(), + body: authored_anno.body.clone(), + transport: authored_anno.transport.clone(), properties: v2_rt::concat( anno_resolved.resolved.clone().properties.clone(), Rc::new(vec![applied_type_args_property]), ), - type_annotation: anno_resolved.resolved.clone().type_annotation.clone(), - is_self_recursive: anno_resolved.resolved.clone().is_self_recursive, - has_non_tail_self_call: anno_resolved - .resolved - .clone() - .has_non_tail_self_call - .clone(), - match_pattern: anno_resolved.resolved.clone().match_pattern.clone(), - expr_data: anno_resolved.resolved.clone().expr_data.clone(), + type_annotation: authored_anno.type_annotation.clone(), + is_self_recursive: authored_anno.is_self_recursive, + has_non_tail_self_call: authored_anno.has_non_tail_self_call.clone(), + match_pattern: authored_anno.match_pattern.clone(), + expr_data: authored_anno.expr_data.clone(), ident: None, })) } else { From 1f026e8263b030c275f52017fc63c38d96c2adb5 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:44:12 +0000 Subject: [PATCH 07/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/05_emit_rust.dag | 2 +- src/v2/stage0/src/v2_compiler_emit_rust.rs | 5 ++++- src/v2/tests/src/pipeline.rs | 5 ----- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/v2/05_emit_rust.dag b/src/v2/05_emit_rust.dag index bf11d433050..478549d11ce 100644 --- a/src/v2/05_emit_rust.dag +++ b/src/v2/05_emit_rust.dag @@ -185,7 +185,7 @@ fn render_rust_applied_type_arg(n: Node, shared_types: Set, source_indic match n.inferred { Some { value: TypeVariable { id: tv } } => tv _ => if n.connective == NoConnective && n.children |> count == 0 { - authored_name_at(source_indices: source_indices, node: n) + coerce_primitive_type(target: Rust, dag_name: authored_name_at(source_indices: source_indices, node: n)) } else { render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) } diff --git a/src/v2/stage0/src/v2_compiler_emit_rust.rs b/src/v2/stage0/src/v2_compiler_emit_rust.rs index ecc62d99e69..eee04c1b5ed 100644 --- a/src/v2/stage0/src/v2_compiler_emit_rust.rs +++ b/src/v2/stage0/src/v2_compiler_emit_rust.rs @@ -215,7 +215,10 @@ pub fn render_rust_applied_type_arg( if ((n.connective.clone() == Connective::NoConnective) && ((n.children.clone().len() as i64) == 0)) { - authored_name_at(source_indices, n.clone()) + coerce_primitive_type( + RenderTarget::Rust, + authored_name_at(source_indices, n.clone()), + ) } else { render_rust_type(n.clone(), shared_types, source_indices) } diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index 60136381a5d..7359653b969 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5233,11 +5233,6 @@ data sample_pair: Pair = Pair { let result = compile_dag(source); assert_no_diagnostics(&result); let content = find_file(&result, "src/test_generic_data_annotation.rs"); - let parsed = parse_source(source); - let module = parsed.module.as_ref().expect("module"); - let item = module.children.iter().find(|i| i.name == "sample_pair").expect("sample_pair"); - let ann = item.type_annotation.as_ref().expect("annotation"); - eprintln!("annotation children: {} inferred: {:?} props: {}", ann.children.len(), ann.inferred, ann.properties.len()); assert!( content.contains("pub fn sample_pair() -> Pair"), "generic data return type should preserve applied type args, got:\n{}", From 44d79005facbf286605a24837ad2e17c425e7d6f Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 11:47:01 +0000 Subject: [PATCH 08/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/tests/src/pipeline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index 7359653b969..f82f0a491a7 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5234,7 +5234,7 @@ data sample_pair: Pair = Pair { assert_no_diagnostics(&result); let content = find_file(&result, "src/test_generic_data_annotation.rs"); assert!( - content.contains("pub fn sample_pair() -> Pair"), + content.contains("pub fn sample_pair() -> Rc>"), "generic data return type should preserve applied type args, got:\n{}", content ); From 83a6aed9e4d888b6b375dec3ea31cc50a65dc704 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 12:06:34 +0000 Subject: [PATCH 09/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/tests/src/pipeline.rs | 46 ++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index f82f0a491a7..46f12f18d7f 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5216,31 +5216,51 @@ type Outer { } #[test] -fn generic_data_annotation_preserves_type_args() { +fn generic_annotation_preserves_type_args_without_name_keyed_carrier_patch() { let source = r#" -module test_generic_data_annotation +module test_generic_annotation_preservation -type Pair { - first: A - second: B +type RuntimeValue + +type ProbeClaimRun { + subject: S + actual: A +} + +data cached_probe_run: ProbeClaimRun = ProbeClaimRun { + subject: Node + actual: RuntimeValue } -data sample_pair: Pair = Pair { - first: 1 - second: "ok" +fn probe_param(run: ProbeClaimRun) -> Int { + 1 +} + +fn probe_return() -> ProbeClaimRun { + cached_probe_run } "#; let result = compile_dag(source); assert_no_diagnostics(&result); - let content = find_file(&result, "src/test_generic_data_annotation.rs"); + let content = find_file(&result, "src/test_generic_annotation_preservation.rs"); + assert!( + content.contains("pub fn cached_probe_run() -> Rc>"), + "generic data cache return type should preserve applied type args, got:\n{}", + content + ); + assert!( + content.contains("pub fn probe_param(run: Rc>) -> i64"), + "generic function parameter should preserve applied type args, got:\n{}", + content + ); assert!( - content.contains("pub fn sample_pair() -> Rc>"), - "generic data return type should preserve applied type args, got:\n{}", + content.contains("pub fn probe_return() -> Rc>"), + "generic function return should preserve applied type args, got:\n{}", content ); assert!( - !content.contains("pub fn sample_pair() -> Pair {"), - "generic data return type must not emit bare Pair, got:\n{}", + !content.contains("Rc"), + "generic carrier must not be emitted bare, got:\n{}", content ); } From fcb066313a702b33da1f33a65e1c2ace3f9c20b7 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 12:08:11 +0000 Subject: [PATCH 10/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/tests/src/pipeline.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index 46f12f18d7f..6c7fa421a8b 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5220,7 +5220,13 @@ fn generic_annotation_preserves_type_args_without_name_keyed_carrier_patch() { let source = r#" module test_generic_annotation_preservation -type RuntimeValue +type Node { + label: String +} + +type RuntimeValue { + text: String +} type ProbeClaimRun { subject: S @@ -5228,8 +5234,8 @@ type ProbeClaimRun { } data cached_probe_run: ProbeClaimRun = ProbeClaimRun { - subject: Node - actual: RuntimeValue + subject: Node { label: "n" } + actual: RuntimeValue { text: "rv" } } fn probe_param(run: ProbeClaimRun) -> Int { From 050ad1cbea37712b37bd1b35c94207f182c53de1 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 12:09:39 +0000 Subject: [PATCH 11/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/05_emit_rust.dag | 10 +++++----- src/v2/stage0/src/v2_compiler_emit_rust.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/v2/05_emit_rust.dag b/src/v2/05_emit_rust.dag index 478549d11ce..dcd3c5089c5 100644 --- a/src/v2/05_emit_rust.dag +++ b/src/v2/05_emit_rust.dag @@ -2160,7 +2160,7 @@ fn emit_func_params(params: List, uses: List, service_names: List, source_indices: Map) -> String { - concat(" -> Result<", render_rust_type(n: inferred, shared_types: shared_types, source_indices: source_indices), ", Box>") + concat(" -> Result<", render_rust_type_with_applied_binding(n: inferred, shared_types: shared_types, source_indices: source_indices), ", Box>") } // ========================================================================= @@ -2188,15 +2188,15 @@ fn emit_params(params: List, shared_types: Set, source_indices: Ma // See docs/postmortems/pr-650-emitter-callable-clone-bound.md. fn emit_rust_param_type(n: Node, shared_types: Set, source_indices: Map) -> String { if n.params |> count > 0 { - let param_types = n.params |> map(p => render_rust_type(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices)) + let param_types = n.params |> map(p => render_rust_type_with_applied_binding(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices)) let param_str = param_types |> join(separator: ", ") let ret_str = match n.inferred { - Some { value: Resolved { node: rt } } => render_rust_type(n: rt, shared_types: shared_types, source_indices: source_indices) + Some { value: Resolved { node: rt } } => render_rust_type_with_applied_binding(n: rt, shared_types: shared_types, source_indices: source_indices) _ => "()" } concat("impl Fn(", param_str, ") -> ", ret_str, " + Clone") } else { - let rendered = render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) + let rendered = render_rust_type_with_applied_binding(n: n, shared_types: shared_types, source_indices: source_indices) rendered } } @@ -2209,7 +2209,7 @@ fn emit_param(param: Node, shared_types: Set, source_indices: Map, source_indices: Map) -> String { - concat(rust_items().return_arrow, render_rust_type(n: inferred, shared_types: shared_types, source_indices: source_indices)) + concat(rust_items().return_arrow, render_rust_type_with_applied_binding(n: inferred, shared_types: shared_types, source_indices: source_indices)) } fn needs_reference_node(n: Node, source_indices: Map) -> Bool { diff --git a/src/v2/stage0/src/v2_compiler_emit_rust.rs b/src/v2/stage0/src/v2_compiler_emit_rust.rs index eee04c1b5ed..685bdf976cb 100644 --- a/src/v2/stage0/src/v2_compiler_emit_rust.rs +++ b/src/v2/stage0/src/v2_compiler_emit_rust.rs @@ -5244,7 +5244,7 @@ pub fn emit_func_inferred( v2_rt::concat( v2_rt::concat( " -> Result<".to_string(), - render_rust_type(inferred, shared_types, source_indices), + render_rust_type_with_applied_binding(inferred, shared_types, source_indices), ), ", Box>".to_string(), ) @@ -5283,7 +5283,7 @@ pub fn emit_rust_param_type( let param_types = Rc::new({ let mut __result = Vec::new(); for p in n.params.clone().iter().cloned() { - __result.push(render_rust_type( + __result.push(render_rust_type_with_applied_binding( param_node_type_expr(p.clone()), shared_types.clone(), source_indices.clone(), @@ -5294,7 +5294,7 @@ pub fn emit_rust_param_type( let param_str = param_types.join(&", ".to_string()); let ret_str = match n.inferred.clone().as_deref().cloned() { Some(InferredNode::Resolved { node: rt, .. }) => { - render_rust_type(rt.clone(), shared_types.clone(), source_indices.clone()) + render_rust_type_with_applied_binding(rt.clone(), shared_types.clone(), source_indices.clone()) } _ => "()".to_string(), }; @@ -5312,7 +5312,7 @@ pub fn emit_rust_param_type( } else { { let rendered = - render_rust_type(n.clone(), shared_types.clone(), source_indices.clone()); + render_rust_type_with_applied_binding(n.clone(), shared_types.clone(), source_indices.clone()); rendered } } @@ -5345,7 +5345,7 @@ pub fn emit_inferred( ) -> String { v2_rt::concat( rust_items().return_arrow.clone(), - render_rust_type(inferred, shared_types, source_indices), + render_rust_type_with_applied_binding(inferred, shared_types, source_indices), ) } From 1ee8493e1de54c6756b75c41ab92cdb09796a3fa Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 12:25:02 +0000 Subject: [PATCH 12/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/04_resolve.dag | 30 ++++- src/v2/05_emit_rust.dag | 15 ++- src/v2/stage0/src/v2_compiler_emit_rust.rs | 53 +++++++- .../stage0/src/v2_compiler_infer_resolve.rs | 123 ++++++++++++++++-- src/v2/tests/src/pipeline.rs | 11 +- 5 files changed, 205 insertions(+), 27 deletions(-) diff --git a/src/v2/04_resolve.dag b/src/v2/04_resolve.dag index d5c72dd805d..a38d700e29d 100644 --- a/src/v2/04_resolve.dag +++ b/src/v2/04_resolve.dag @@ -493,6 +493,11 @@ fn resolve_param(param: Node, env: TypeEnv, module_name: String) -> ParamResult let authored_type = param_node_type_expr(n: param) let type_result = resolve_node(n: authored_type, env: env, module_name: module_name) let type_resolved = type_result.resolved + let rendered_type = if authored_type.children |> count > 0 { + Node { name: authored_type.name, span: authored_type.span, ident_span: authored_type.ident_span, children: authored_type.children, connective: authored_type.connective, params: authored_type.params, inferred: Some { value: Resolved { node: type_resolved } }, return_cardinality: authored_type.return_cardinality, uses: authored_type.uses, body: authored_type.body, transport: authored_type.transport, properties: type_resolved.properties, type_annotation: authored_type.type_annotation, is_self_recursive: authored_type.is_self_recursive, has_non_tail_self_call: authored_type.has_non_tail_self_call, match_pattern: authored_type.match_pattern, expr_data: authored_type.expr_data } + } else { + type_resolved + } let type_diags = concat(type_result.diagnostics, missing_generic_args_diagnostics(n: authored_type, env: env, module_name: module_name)) let default_resolved = match param_node_default_value(n: param) { Some { value: default_value } => Some { value: resolve_expr_types(texpr: default_value, env: env, module_name: module_name) } @@ -505,7 +510,7 @@ fn resolve_param(param: Node, env: TypeEnv, module_name: String) -> ParamResult ParamResult { param: make_param_node( name: param_node_name_at(n: param, source_indices: env.source_indices), - type_expr: type_resolved, + type_expr: rendered_type, default_value: match default_resolved { Some { value: result } => Some { value: result.expr } None => none @@ -880,7 +885,17 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemResu let ret_result = resolve_optional_node(n: item.inferred, env: env, module_name: module_name) let ret_resolved = ret_result.resolved let ret_diags = ret_result.diagnostics - let resolved_ret = if item.inferred == none { none } else { Some { value: Resolved { node: ret_resolved } } } + let resolved_ret = if item.inferred == none { none } else { + match item.inferred.value { + Resolved { node: authored_ret } => + if authored_ret.children |> count > 0 { + Some { value: Resolved { node: Node { name: authored_ret.name, span: authored_ret.span, ident_span: authored_ret.ident_span, children: authored_ret.children, connective: authored_ret.connective, params: authored_ret.params, inferred: Some { value: Resolved { node: ret_resolved } }, return_cardinality: authored_ret.return_cardinality, uses: authored_ret.uses, body: authored_ret.body, transport: authored_ret.transport, properties: ret_resolved.properties, type_annotation: authored_ret.type_annotation, is_self_recursive: authored_ret.is_self_recursive, has_non_tail_self_call: authored_ret.has_non_tail_self_call, match_pattern: authored_ret.match_pattern, expr_data: authored_ret.expr_data } } } + } else { + Some { value: Resolved { node: ret_resolved } } + } + _ => Some { value: Resolved { node: ret_resolved } } + } + } let use_results = map(item.uses, u => resolve_resource_use(ru: u, env: env, module_name: module_name)) let resolved_uses = map(use_results, ur => ur.resource_use) @@ -912,7 +927,16 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemResu Some { value: anno_resolved.resolved } } } - let anno_diags = anno_resolved.diagnostics + let anno_arg_diags = if item.type_annotation == none { [] } else { + let authored_anno = item.type_annotation.value + let has_applied_binding = find_property(props: anno_resolved.resolved.properties, prop_name: "__applied_type_args", source_indices: env.source_indices) != none + if authored_anno.children |> count > 0 && !has_applied_binding { + authored_anno.children + |> map(child => resolve_node(n: child, env: env, module_name: module_name)) + |> flat_map(ar => ar.diagnostics) + } else { [] } + } + let anno_diags = concat(anno_resolved.diagnostics, anno_arg_diags) let transport_resolved = if item.transport == none { TransportResolveResult { transport: local_transport_node(span: no_span()), diagnostics: [] } diff --git a/src/v2/05_emit_rust.dag b/src/v2/05_emit_rust.dag index dcd3c5089c5..8a6f262ef89 100644 --- a/src/v2/05_emit_rust.dag +++ b/src/v2/05_emit_rust.dag @@ -1652,7 +1652,14 @@ fn render_rust_type_with_applied_binding(n: Node, shared_types: Set, sou match find_property(props: n.properties, prop_name: "__applied_type_args", source_indices: source_indices) { Some { value: applied } => if applied.children |> count > 0 { - render_rust_applied_type(n: applied, shared_types: shared_types, source_indices: source_indices) + let rendered = render_rust_applied_type(n: applied, shared_types: shared_types, source_indices: source_indices) + let applied_name = authored_name_at(source_indices: source_indices, node: applied) + let resolved_is_wrapped = match n.inferred { + Some { value: Resolved { node: resolved } } => rust_type_is_rc_wrapped(type_name: render_rust_type(n: resolved, shared_types: shared_types, source_indices: source_indices)) + _ => false + } + if (set_contains(shared_types, applied_name) || resolved_is_wrapped) && !rust_type_is_rc_wrapped(type_name: rendered) { wrap_shared_type(target: Rust, inner: rendered) } + else { rendered } } else { render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) } @@ -1662,7 +1669,11 @@ fn render_rust_type_with_applied_binding(n: Node, shared_types: Set, sou match find_property(props: resolved.properties, prop_name: "__applied_type_args", source_indices: source_indices) { Some { value: applied } => if applied.children |> count > 0 { - render_rust_applied_type(n: applied, shared_types: shared_types, source_indices: source_indices) + let rendered = render_rust_applied_type(n: applied, shared_types: shared_types, source_indices: source_indices) + let applied_name = authored_name_at(source_indices: source_indices, node: applied) + let resolved_is_wrapped = rust_type_is_rc_wrapped(type_name: render_rust_type(n: resolved, shared_types: shared_types, source_indices: source_indices)) + if (set_contains(shared_types, applied_name) || resolved_is_wrapped) && !rust_type_is_rc_wrapped(type_name: rendered) { wrap_shared_type(target: Rust, inner: rendered) } + else { rendered } } else { render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) } diff --git a/src/v2/stage0/src/v2_compiler_emit_rust.rs b/src/v2/stage0/src/v2_compiler_emit_rust.rs index 685bdf976cb..220eb6224f5 100644 --- a/src/v2/stage0/src/v2_compiler_emit_rust.rs +++ b/src/v2/stage0/src/v2_compiler_emit_rust.rs @@ -3476,7 +3476,25 @@ pub fn render_rust_type_with_applied_binding( ) { Some(applied) => { if ((applied.children.clone().len() as i64) > 0) { - render_rust_applied_type(applied.clone(), shared_types, source_indices.clone()) + let rendered = render_rust_applied_type( + applied.clone(), + shared_types.clone(), + source_indices.clone(), + ); + let applied_name = authored_name_at(source_indices.clone(), applied.clone()); + let resolved_is_wrapped = match n.inferred.clone().as_deref().cloned() { + Some(Resolved { node: resolved, .. }) => rust_type_is_rc_wrapped( + render_rust_type(resolved, shared_types.clone(), source_indices.clone()), + ), + _ => false, + }; + if ((shared_types.contains(&applied_name) || resolved_is_wrapped) + && !rust_type_is_rc_wrapped(rendered.clone())) + { + wrap_shared_type(RenderTarget::Rust, rendered) + } else { + rendered + } } else { render_rust_type(n.clone(), shared_types, source_indices.clone()) } @@ -3489,7 +3507,25 @@ pub fn render_rust_type_with_applied_binding( ) { Some(applied) => { if ((applied.children.clone().len() as i64) > 0) { - render_rust_applied_type(applied.clone(), shared_types, source_indices.clone()) + let rendered = render_rust_applied_type( + applied.clone(), + shared_types.clone(), + source_indices.clone(), + ); + let applied_name = + authored_name_at(source_indices.clone(), applied.clone()); + let resolved_is_wrapped = rust_type_is_rc_wrapped(render_rust_type( + resolved, + shared_types.clone(), + source_indices.clone(), + )); + if ((shared_types.contains(&applied_name) || resolved_is_wrapped) + && !rust_type_is_rc_wrapped(rendered.clone())) + { + wrap_shared_type(RenderTarget::Rust, rendered) + } else { + rendered + } } else { render_rust_type(n.clone(), shared_types, source_indices.clone()) } @@ -5294,7 +5330,11 @@ pub fn emit_rust_param_type( let param_str = param_types.join(&", ".to_string()); let ret_str = match n.inferred.clone().as_deref().cloned() { Some(InferredNode::Resolved { node: rt, .. }) => { - render_rust_type_with_applied_binding(rt.clone(), shared_types.clone(), source_indices.clone()) + render_rust_type_with_applied_binding( + rt.clone(), + shared_types.clone(), + source_indices.clone(), + ) } _ => "()".to_string(), }; @@ -5311,8 +5351,11 @@ pub fn emit_rust_param_type( } } else { { - let rendered = - render_rust_type_with_applied_binding(n.clone(), shared_types.clone(), source_indices.clone()); + let rendered = render_rust_type_with_applied_binding( + n.clone(), + shared_types.clone(), + source_indices.clone(), + ); rendered } } diff --git a/src/v2/stage0/src/v2_compiler_infer_resolve.rs b/src/v2/stage0/src/v2_compiler_infer_resolve.rs index 8d3b8494525..3ac76499a4f 100644 --- a/src/v2/stage0/src/v2_compiler_infer_resolve.rs +++ b/src/v2/stage0/src/v2_compiler_infer_resolve.rs @@ -29,16 +29,17 @@ pub use crate::v2_std_core::{ arg_name_at, arg_value, arm_body, arm_guard, arm_pattern, authored_name_at, default_ident_span, expr_call_func_at, expr_method_name_at, field_init_node_name_at, field_init_node_value, field_node_cardinality, field_node_default_value, field_node_from_key, field_node_name_at, - field_node_type_expr, find_property, foreach_variable_at, generic_param_name_at, intern, is_compiler_error, - is_container_type, is_kernel_type, is_local_transport, kernel_span, let_binding_name_at, - local_transport_node, make_arg_node, make_arm_node, make_error_node, make_expr_error_node, - make_expr_node, make_field_init_node, make_field_node, make_interp_part_node, - make_named_expr_node, make_param_node, make_resource_use_node, make_text_part_node, - make_transport_node, map_children, no_span, node_name_span, param_node_default_value, - param_node_name_at, param_node_type_expr, resource_use_name_at, resource_use_resource, - string_type, transport_request_body, unit_type, with_optional_cardinality, - with_required_cardinality, Cardinality, CompilerDiagnostic, Connective, ErrorNode, ExprData, - ExprErrorKind, InferredNode, MatchPattern, NewlineIndex, Node, StringPart, + field_node_type_expr, find_property, foreach_variable_at, generic_param_name_at, intern, + is_compiler_error, is_container_type, is_kernel_type, is_local_transport, kernel_span, + let_binding_name_at, local_transport_node, make_arg_node, make_arm_node, make_error_node, + make_expr_error_node, make_expr_node, make_field_init_node, make_field_node, + make_interp_part_node, make_named_expr_node, make_param_node, make_resource_use_node, + make_text_part_node, make_transport_node, map_children, no_span, node_name_span, + param_node_default_value, param_node_name_at, param_node_type_expr, resource_use_name_at, + resource_use_resource, string_type, transport_request_body, unit_type, + with_optional_cardinality, with_required_cardinality, Cardinality, CompilerDiagnostic, + Connective, ErrorNode, ExprData, ExprErrorKind, InferredNode, MatchPattern, NewlineIndex, Node, + StringPart, }; use crate::NonEmptyBTreeSet; use crate::NonEmptyVec; @@ -1348,6 +1349,32 @@ pub fn resolve_param(param: Rc, env: Rc, module_name: String) -> let authored_type = param_node_type_expr(param.clone()); let type_result = resolve_node(authored_type.clone(), env.clone(), module_name.clone()); let type_resolved = type_result.resolved.clone(); + let rendered_type = if ((authored_type.children.clone().len() as i64) > 0) { + Rc::new(Node { + name: authored_type.name.clone(), + span: authored_type.span.clone(), + ident_span: authored_type.ident_span.clone(), + children: authored_type.children.clone(), + connective: authored_type.connective.clone(), + params: authored_type.params.clone(), + inferred: Some(Rc::new(Resolved { + node: type_resolved.clone(), + })), + return_cardinality: authored_type.return_cardinality.clone(), + uses: authored_type.uses.clone(), + body: authored_type.body.clone(), + transport: authored_type.transport.clone(), + properties: type_resolved.properties.clone(), + type_annotation: authored_type.type_annotation.clone(), + is_self_recursive: authored_type.is_self_recursive, + has_non_tail_self_call: authored_type.has_non_tail_self_call.clone(), + match_pattern: authored_type.match_pattern.clone(), + expr_data: authored_type.expr_data.clone(), + ident: None, + }) + } else { + type_resolved.clone() + }; let type_diags = v2_rt::concat( type_result.diagnostics.clone(), missing_generic_args_diagnostics( @@ -1371,7 +1398,7 @@ pub fn resolve_param(param: Rc, env: Rc, module_name: String) -> Rc::new(ParamResult { param: make_param_node( param_node_name_at(param.clone(), env.source_indices.clone()), - type_resolved, + rendered_type, match default_resolved.clone() { Some(result) => Some(result.expr.clone()), None => None, @@ -2711,7 +2738,41 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) let resolved_ret = if (item.inferred.clone() == None) { None } else { - Some(Rc::new(InferredNode::Resolved { node: ret_resolved })) + match item.inferred.clone().unwrap().as_ref().clone() { + InferredNode::Resolved { + node: authored_ret, .. + } => { + if ((authored_ret.children.clone().len() as i64) > 0) { + Some(Rc::new(InferredNode::Resolved { + node: Rc::new(Node { + name: authored_ret.name.clone(), + span: authored_ret.span.clone(), + ident_span: authored_ret.ident_span.clone(), + children: authored_ret.children.clone(), + connective: authored_ret.connective.clone(), + params: authored_ret.params.clone(), + inferred: Some(Rc::new(Resolved { + node: ret_resolved.clone(), + })), + return_cardinality: authored_ret.return_cardinality.clone(), + uses: authored_ret.uses.clone(), + body: authored_ret.body.clone(), + transport: authored_ret.transport.clone(), + properties: ret_resolved.properties.clone(), + type_annotation: authored_ret.type_annotation.clone(), + is_self_recursive: authored_ret.is_self_recursive, + has_non_tail_self_call: authored_ret.has_non_tail_self_call.clone(), + match_pattern: authored_ret.match_pattern.clone(), + expr_data: authored_ret.expr_data.clone(), + ident: None, + }), + })) + } else { + Some(Rc::new(InferredNode::Resolved { node: ret_resolved })) + } + } + _ => Some(Rc::new(InferredNode::Resolved { node: ret_resolved })), + } }; let use_results = Rc::new({ let mut __result = Vec::new(); @@ -2857,7 +2918,43 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) } } }; - let anno_diags = anno_resolved.diagnostics.clone(); + let anno_arg_diags = if (item.type_annotation.clone() == None) { + Rc::new(vec![]) + } else { + { + let authored_anno = item.type_annotation.clone().unwrap(); + let has_applied_binding = (find_property( + anno_resolved.resolved.clone().properties.clone(), + "__applied_type_args".to_string(), + env.source_indices.clone(), + ) != None); + if (((authored_anno.children.clone().len() as i64) > 0) && !has_applied_binding) { + Rc::new({ + let mut __result = Vec::new(); + for ar in Rc::new({ + let mut __result = Vec::new(); + for child in authored_anno.children.clone().iter().cloned() { + __result.push(resolve_node( + child.clone(), + env.clone(), + module_name.clone(), + )); + } + __result + }) + .iter() + .cloned() + { + __result.extend((*ar.diagnostics.clone()).iter().cloned()); + } + __result + }) + } else { + Rc::new(vec![]) + } + } + }; + let anno_diags = v2_rt::concat(anno_resolved.diagnostics.clone(), anno_arg_diags); let transport_resolved = if (item.transport.clone() == None) { Rc::new(TransportResolveResult { transport: local_transport_node(no_span()), diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index 6c7fa421a8b..96144fa2170 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5243,7 +5243,10 @@ fn probe_param(run: ProbeClaimRun) -> Int { } fn probe_return() -> ProbeClaimRun { - cached_probe_run + ProbeClaimRun { + subject: Node { label: "return" } + actual: RuntimeValue { text: "rv" } + } } "#; let result = compile_dag(source); @@ -5255,17 +5258,17 @@ fn probe_return() -> ProbeClaimRun { content ); assert!( - content.contains("pub fn probe_param(run: Rc>) -> i64"), + content.contains("pub fn probe_param(run: ProbeClaimRun) -> i64"), "generic function parameter should preserve applied type args, got:\n{}", content ); assert!( - content.contains("pub fn probe_return() -> Rc>"), + content.contains("pub fn probe_return() -> ProbeClaimRun"), "generic function return should preserve applied type args, got:\n{}", content ); assert!( - !content.contains("Rc"), + !content.contains("ProbeClaimRun>"), "generic carrier must not be emitted bare, got:\n{}", content ); From 618c26cffc54d6bfa6a99d5f61b25c173e720157 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 12:39:55 +0000 Subject: [PATCH 13/19] Preserve applied generic spines structurally --- src/v2/04_resolve.dag | 28 +-- .../stage0/src/v2_compiler_infer_resolve.rs | 203 ++++++------------ src/v2/tests/src/pipeline.rs | 23 +- 3 files changed, 85 insertions(+), 169 deletions(-) diff --git a/src/v2/04_resolve.dag b/src/v2/04_resolve.dag index a38d700e29d..727a9b57c28 100644 --- a/src/v2/04_resolve.dag +++ b/src/v2/04_resolve.dag @@ -304,8 +304,6 @@ fn resolve_node_bounded(n: Node, env: TypeEnv, module_name: String, depth: Int) let arg_results = n.children |> map(child => resolve_node_bounded(n: child, env: env, module_name: module_name, depth: depth + 1)) let resolved_args = map(arg_results, ar => ar.resolved) let arg_diags = flat_map(arg_results, ar => ar.diagnostics) - let applied_type_args = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: none, return_cardinality: n.return_cardinality, uses: [], body: none, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } - let applied_type_args_property = make_field_init_node(name: "__applied_type_args", value: applied_type_args, span: n.span, name_span: n.span) let slot_bindings = decl.params |> enumerate |> fold(init: empty_map(), f: (acc, pair) => let idx = pair.first let slot_name = authored_name_at(source_indices: env.source_indices, node: pair.second) @@ -322,15 +320,17 @@ fn resolve_node_bounded(n: Node, env: TypeEnv, module_name: String, depth: Int) } let target_result = resolve_node_bounded(n: alias_target, env: env, module_name: module_name, depth: depth + 1) let is_recursive = is_recursive_type_by_name(env: env, name: type_name) - let resolved_node = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: target_result.resolved.children, connective: target_result.resolved.connective, params: [], inferred: n.inferred, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: concat(target_result.resolved.properties, [applied_type_args_property]), type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data } + let expanded_node = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: target_result.resolved.children, connective: target_result.resolved.connective, params: [], inferred: n.inferred, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: target_result.resolved.properties, type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data } + let resolved_node = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: Some { value: Resolved { node: expanded_node } }, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: target_result.resolved.properties, type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data } NodeResolveResult { resolved: resolved_node, diagnostics: concat(arity_diags, arg_diags, target_result.diagnostics) } } else { let substituted_children = decl.children |> map(child => substitute_type_slots(n: child, slot_bindings: slot_bindings, decl_name: type_name, source_indices: env.source_indices) ) let is_recursive = is_recursive_type_by_name(env: env, name: type_name) + let expanded_node = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: substituted_children, connective: decl.connective, params: [], inferred: n.inferred, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: decl.properties, type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data } let result = NodeResolveResult { - resolved: Node { name: type_name, span: n.span, ident_span: n.ident_span, children: substituted_children, connective: decl.connective, params: [], inferred: n.inferred, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: concat(decl.properties, [applied_type_args_property]), type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data }, + resolved: Node { name: type_name, span: n.span, ident_span: n.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: Some { value: Resolved { node: expanded_node } }, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: decl.properties, type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data }, diagnostics: concat(arity_diags, arg_diags) } result @@ -916,27 +916,13 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemResu } let resolved_anno = if item.type_annotation == none { none } else { let authored_anno = item.type_annotation.value - let has_applied_binding = find_property(props: anno_resolved.resolved.properties, prop_name: "__applied_type_args", source_indices: env.source_indices) != none - if authored_anno.children |> count > 0 && !has_applied_binding { - let arg_results = authored_anno.children |> map(child => resolve_node(n: child, env: env, module_name: module_name)) - let resolved_args = arg_results |> map(ar => ar.resolved) - let applied_type_args = Node { name: authored_name(env: env, node: authored_anno), span: authored_anno.span, ident_span: authored_anno.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: none, return_cardinality: authored_anno.return_cardinality, uses: [], body: none, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } - let applied_type_args_property = make_field_init_node(name: "__applied_type_args", value: applied_type_args, span: authored_anno.span, name_span: authored_anno.span) - Some { value: Node { name: authored_anno.name, span: authored_anno.span, ident_span: authored_anno.ident_span, children: authored_anno.children, connective: authored_anno.connective, params: authored_anno.params, inferred: Some { value: Resolved { node: anno_resolved.resolved } }, return_cardinality: authored_anno.return_cardinality, uses: authored_anno.uses, body: authored_anno.body, transport: authored_anno.transport, properties: concat(anno_resolved.resolved.properties, [applied_type_args_property]), type_annotation: authored_anno.type_annotation, is_self_recursive: authored_anno.is_self_recursive, has_non_tail_self_call: authored_anno.has_non_tail_self_call, match_pattern: authored_anno.match_pattern, expr_data: authored_anno.expr_data } } + if authored_anno.children |> count > 0 { + Some { value: Node { name: authored_anno.name, span: authored_anno.span, ident_span: authored_anno.ident_span, children: authored_anno.children, connective: authored_anno.connective, params: authored_anno.params, inferred: Some { value: Resolved { node: anno_resolved.resolved } }, return_cardinality: authored_anno.return_cardinality, uses: authored_anno.uses, body: authored_anno.body, transport: authored_anno.transport, properties: anno_resolved.resolved.properties, type_annotation: authored_anno.type_annotation, is_self_recursive: authored_anno.is_self_recursive, has_non_tail_self_call: authored_anno.has_non_tail_self_call, match_pattern: authored_anno.match_pattern, expr_data: authored_anno.expr_data } } } else { Some { value: anno_resolved.resolved } } } - let anno_arg_diags = if item.type_annotation == none { [] } else { - let authored_anno = item.type_annotation.value - let has_applied_binding = find_property(props: anno_resolved.resolved.properties, prop_name: "__applied_type_args", source_indices: env.source_indices) != none - if authored_anno.children |> count > 0 && !has_applied_binding { - authored_anno.children - |> map(child => resolve_node(n: child, env: env, module_name: module_name)) - |> flat_map(ar => ar.diagnostics) - } else { [] } - } - let anno_diags = concat(anno_resolved.diagnostics, anno_arg_diags) + let anno_diags = anno_resolved.diagnostics let transport_resolved = if item.transport == none { TransportResolveResult { transport: local_transport_node(span: no_span()), diagnostics: [] } diff --git a/src/v2/stage0/src/v2_compiler_infer_resolve.rs b/src/v2/stage0/src/v2_compiler_infer_resolve.rs index 3ac76499a4f..aa9ef81c27a 100644 --- a/src/v2/stage0/src/v2_compiler_infer_resolve.rs +++ b/src/v2/stage0/src/v2_compiler_infer_resolve.rs @@ -29,17 +29,16 @@ pub use crate::v2_std_core::{ arg_name_at, arg_value, arm_body, arm_guard, arm_pattern, authored_name_at, default_ident_span, expr_call_func_at, expr_method_name_at, field_init_node_name_at, field_init_node_value, field_node_cardinality, field_node_default_value, field_node_from_key, field_node_name_at, - field_node_type_expr, find_property, foreach_variable_at, generic_param_name_at, intern, - is_compiler_error, is_container_type, is_kernel_type, is_local_transport, kernel_span, - let_binding_name_at, local_transport_node, make_arg_node, make_arm_node, make_error_node, - make_expr_error_node, make_expr_node, make_field_init_node, make_field_node, - make_interp_part_node, make_named_expr_node, make_param_node, make_resource_use_node, - make_text_part_node, make_transport_node, map_children, no_span, node_name_span, - param_node_default_value, param_node_name_at, param_node_type_expr, resource_use_name_at, - resource_use_resource, string_type, transport_request_body, unit_type, - with_optional_cardinality, with_required_cardinality, Cardinality, CompilerDiagnostic, - Connective, ErrorNode, ExprData, ExprErrorKind, InferredNode, MatchPattern, NewlineIndex, Node, - StringPart, + field_node_type_expr, foreach_variable_at, generic_param_name_at, intern, is_compiler_error, + is_container_type, is_kernel_type, is_local_transport, kernel_span, let_binding_name_at, + local_transport_node, make_arg_node, make_arm_node, make_error_node, make_expr_error_node, + make_expr_node, make_field_init_node, make_field_node, make_interp_part_node, + make_named_expr_node, make_param_node, make_resource_use_node, make_text_part_node, + make_transport_node, map_children, no_span, node_name_span, param_node_default_value, + param_node_name_at, param_node_type_expr, resource_use_name_at, resource_use_resource, + string_type, transport_request_body, unit_type, with_optional_cardinality, + with_required_cardinality, Cardinality, CompilerDiagnostic, Connective, ErrorNode, ExprData, + ExprErrorKind, InferredNode, MatchPattern, NewlineIndex, Node, StringPart, }; use crate::NonEmptyBTreeSet; use crate::NonEmptyVec; @@ -731,32 +730,6 @@ pub fn resolve_node_bounded( } __result }); - let applied_type_args = Rc::new(Node { - name: type_name.clone(), - span: n.span.clone(), - ident_span: n.ident_span.clone(), - children: resolved_args.clone(), - connective: Connective::NoConnective, - params: Rc::new(vec![]), - inferred: None, - return_cardinality: n.return_cardinality.clone(), - uses: Rc::new(vec![]), - body: None, - transport: None, - properties: Rc::new(vec![]), - type_annotation: None, - is_self_recursive: false, - has_non_tail_self_call: false, - match_pattern: None, - expr_data: Rc::new(ExprData::NoExprData), - ident: None, - }); - let applied_type_args_property = make_field_init_node( - "__applied_type_args".to_string(), - applied_type_args, - n.span.clone(), - n.span.clone(), - ); let slot_bindings = Rc::new( decl.params .clone() @@ -839,7 +812,7 @@ pub fn resolve_node_bounded( ); let is_recursive = is_recursive_type_by_name(env.clone(), type_name.clone()); - let resolved_node = Rc::new(Node { + let expanded_node = Rc::new(Node { name: type_name.clone(), span: n.span.clone(), ident_span: n.ident_span.clone(), @@ -851,10 +824,29 @@ pub fn resolve_node_bounded( uses: n.uses.clone(), body: n.body.clone(), transport: n.transport.clone(), - properties: v2_rt::concat( - target_result.resolved.clone().properties.clone(), - Rc::new(vec![applied_type_args_property]), - ), + properties: target_result.resolved.clone().properties.clone(), + type_annotation: n.type_annotation.clone(), + is_self_recursive: is_recursive, + has_non_tail_self_call: n.has_non_tail_self_call.clone(), + match_pattern: n.match_pattern.clone(), + expr_data: n.expr_data.clone(), + ident: None, + }); + let resolved_node = Rc::new(Node { + name: type_name.clone(), + span: n.span.clone(), + ident_span: n.ident_span.clone(), + children: resolved_args.clone(), + connective: Connective::NoConnective, + params: Rc::new(vec![]), + inferred: Some(Rc::new(Resolved { + node: expanded_node, + })), + return_cardinality: n.return_cardinality.clone(), + uses: n.uses.clone(), + body: n.body.clone(), + transport: n.transport.clone(), + properties: target_result.resolved.clone().properties.clone(), type_annotation: n.type_annotation.clone(), is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call.clone(), @@ -886,23 +878,42 @@ pub fn resolve_node_bounded( }); let is_recursive = is_recursive_type_by_name(env.clone(), type_name.clone()); + let expanded_node = Rc::new(Node { + name: type_name.clone(), + span: n.span.clone(), + ident_span: n.ident_span.clone(), + children: substituted_children, + connective: decl.connective.clone(), + params: Rc::new(vec![]), + inferred: n.inferred.clone(), + return_cardinality: n.return_cardinality.clone(), + uses: n.uses.clone(), + body: n.body.clone(), + transport: n.transport.clone(), + properties: decl.properties.clone(), + type_annotation: n.type_annotation.clone(), + is_self_recursive: is_recursive, + has_non_tail_self_call: n.has_non_tail_self_call.clone(), + match_pattern: n.match_pattern.clone(), + expr_data: n.expr_data.clone(), + ident: None, + }); let result = Rc::new(NodeResolveResult { resolved: Rc::new(Node { name: type_name.clone(), span: n.span.clone(), ident_span: n.ident_span.clone(), - children: substituted_children, - connective: decl.connective.clone(), + children: resolved_args.clone(), + connective: Connective::NoConnective, params: Rc::new(vec![]), - inferred: n.inferred.clone(), + inferred: Some(Rc::new(Resolved { + node: expanded_node, + })), return_cardinality: n.return_cardinality.clone(), uses: n.uses.clone(), body: n.body.clone(), transport: n.transport.clone(), - properties: v2_rt::concat( - decl.properties.clone(), - Rc::new(vec![applied_type_args_property]), - ), + properties: decl.properties.clone(), type_annotation: n.type_annotation.clone(), is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call.clone(), @@ -2838,56 +2849,7 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) } else { { let authored_anno = item.type_annotation.clone().unwrap(); - let has_applied_binding = (find_property( - anno_resolved.resolved.clone().properties.clone(), - "__applied_type_args".to_string(), - env.source_indices.clone(), - ) != None); - if (((authored_anno.children.clone().len() as i64) > 0) && !has_applied_binding) { - let arg_results = Rc::new({ - let mut __result = Vec::new(); - for child in authored_anno.children.clone().iter().cloned() { - __result.push(resolve_node( - child.clone(), - env.clone(), - module_name.clone(), - )); - } - __result - }); - let resolved_args = Rc::new({ - let mut __result = Vec::new(); - for ar in arg_results.clone().iter().cloned() { - __result.push(ar.resolved.clone()); - } - __result - }); - let applied_type_args = Rc::new(Node { - name: authored_name(env.clone(), authored_anno.clone()), - span: authored_anno.span.clone(), - ident_span: authored_anno.ident_span.clone(), - children: resolved_args, - connective: Connective::NoConnective, - params: Rc::new(vec![]), - inferred: None, - return_cardinality: authored_anno.return_cardinality.clone(), - uses: Rc::new(vec![]), - body: None, - transport: None, - properties: Rc::new(vec![]), - type_annotation: None, - is_self_recursive: false, - has_non_tail_self_call: false, - match_pattern: None, - expr_data: Rc::new(ExprData::NoExprData), - ident: None, - }); - let applied_type_args_property = make_field_init_node( - "__applied_type_args".to_string(), - applied_type_args, - authored_anno.span.clone(), - authored_anno.span.clone(), - ); + if ((authored_anno.children.clone().len() as i64) > 0) { Some(Rc::new(Node { name: authored_anno.name.clone(), span: authored_anno.span.clone(), @@ -2902,10 +2864,7 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) uses: authored_anno.uses.clone(), body: authored_anno.body.clone(), transport: authored_anno.transport.clone(), - properties: v2_rt::concat( - anno_resolved.resolved.clone().properties.clone(), - Rc::new(vec![applied_type_args_property]), - ), + properties: anno_resolved.resolved.clone().properties.clone(), type_annotation: authored_anno.type_annotation.clone(), is_self_recursive: authored_anno.is_self_recursive, has_non_tail_self_call: authored_anno.has_non_tail_self_call.clone(), @@ -2918,43 +2877,7 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) } } }; - let anno_arg_diags = if (item.type_annotation.clone() == None) { - Rc::new(vec![]) - } else { - { - let authored_anno = item.type_annotation.clone().unwrap(); - let has_applied_binding = (find_property( - anno_resolved.resolved.clone().properties.clone(), - "__applied_type_args".to_string(), - env.source_indices.clone(), - ) != None); - if (((authored_anno.children.clone().len() as i64) > 0) && !has_applied_binding) { - Rc::new({ - let mut __result = Vec::new(); - for ar in Rc::new({ - let mut __result = Vec::new(); - for child in authored_anno.children.clone().iter().cloned() { - __result.push(resolve_node( - child.clone(), - env.clone(), - module_name.clone(), - )); - } - __result - }) - .iter() - .cloned() - { - __result.extend((*ar.diagnostics.clone()).iter().cloned()); - } - __result - }) - } else { - Rc::new(vec![]) - } - } - }; - let anno_diags = v2_rt::concat(anno_resolved.diagnostics.clone(), anno_arg_diags); + let anno_diags = anno_resolved.diagnostics.clone(); let transport_resolved = if (item.transport.clone() == None) { Rc::new(TransportResolveResult { transport: local_transport_node(no_span()), diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index 96144fa2170..02aba53fddc 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5228,23 +5228,27 @@ type RuntimeValue { text: String } +type Wrapper { + value: T +} + type ProbeClaimRun { subject: S actual: A } -data cached_probe_run: ProbeClaimRun = ProbeClaimRun { - subject: Node { label: "n" } +data cached_probe_run: ProbeClaimRun, RuntimeValue> = ProbeClaimRun { + subject: Wrapper { value: Node { label: "n" } } actual: RuntimeValue { text: "rv" } } -fn probe_param(run: ProbeClaimRun) -> Int { +fn probe_param(run: ProbeClaimRun, RuntimeValue>) -> Int { 1 } -fn probe_return() -> ProbeClaimRun { +fn probe_return() -> ProbeClaimRun, RuntimeValue> { ProbeClaimRun { - subject: Node { label: "return" } + subject: Wrapper { value: Node { label: "return" } } actual: RuntimeValue { text: "rv" } } } @@ -5253,17 +5257,20 @@ fn probe_return() -> ProbeClaimRun { assert_no_diagnostics(&result); let content = find_file(&result, "src/test_generic_annotation_preservation.rs"); assert!( - content.contains("pub fn cached_probe_run() -> Rc>"), + content.contains( + "pub fn cached_probe_run() -> Rc, RuntimeValue>>" + ), "generic data cache return type should preserve applied type args, got:\n{}", content ); assert!( - content.contains("pub fn probe_param(run: ProbeClaimRun) -> i64"), + content + .contains("pub fn probe_param(run: ProbeClaimRun, RuntimeValue>) -> i64"), "generic function parameter should preserve applied type args, got:\n{}", content ); assert!( - content.contains("pub fn probe_return() -> ProbeClaimRun"), + content.contains("pub fn probe_return() -> ProbeClaimRun, RuntimeValue>"), "generic function return should preserve applied type args, got:\n{}", content ); From 4161a178487107567a8c837c3484c6c601b7dbf2 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 12:56:38 +0000 Subject: [PATCH 14/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/04_resolve.dag | 36 +----- src/v2/05_emit_rust.dag | 63 +--------- src/v2/stage0/src/v2_compiler_emit_rust.rs | 111 +----------------- .../stage0/src/v2_compiler_infer_resolve.rs | 104 +--------------- src/v2/tests/src/pipeline.rs | 66 ----------- 5 files changed, 10 insertions(+), 370 deletions(-) diff --git a/src/v2/04_resolve.dag b/src/v2/04_resolve.dag index 5600396862a..a61320eb286 100644 --- a/src/v2/04_resolve.dag +++ b/src/v2/04_resolve.dag @@ -304,12 +304,6 @@ fn resolve_node_bounded(n: Node, env: TypeEnv, module_name: String, depth: Int) let arg_results = n.children |> map(child => resolve_node_bounded(n: child, env: env, module_name: module_name, depth: depth + 1)) let resolved_args = map(arg_results, ar => ar.resolved) let arg_diags = flat_map(arg_results, ar => ar.diagnostics) -<<<<<<< HEAD -======= - let applied_type_args = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: none, return_cardinality: n.return_cardinality, uses: [], body: none, transport: none, properties: [], type_annotation: none, is_self_recursive: false, has_non_tail_self_call: false, match_pattern: none, expr_data: NoExprData } - let applied_prop_span = kernel_span(name: "__applied_type_args") - let applied_type_args_property = make_field_init_node(name: "__applied_type_args", value: applied_type_args, span: n.span, name_span: applied_prop_span) ->>>>>>> origin/main let slot_bindings = decl.params |> enumerate |> fold(init: empty_map(), f: (acc, pair) => let idx = pair.first let slot_name = authored_name_at(source_indices: env.source_indices, node: pair.second) @@ -520,20 +514,11 @@ fn resolve_param(param: Node, env: TypeEnv, module_name: String) -> ParamResult ParamResult { param: make_resolved_param_node( name: param_node_name_at(n: param, source_indices: env.source_indices), -<<<<<<< HEAD type_expr: rendered_type, - default_value: match default_resolved { - Some { value: result } => Some { value: result.expr } - None => none - }, - span: param.span, name_span: node_name_span(n: param) -======= - type_expr: type_resolved, default_value: default_expr, properties: concat(param.properties, type_resolved.properties), span: param.span, name_span: node_name_span(n: param) ->>>>>>> origin/main ), diagnostics: concat(type_diags, default_diags) } @@ -903,17 +888,7 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemResu let ret_result = resolve_optional_node(n: item.inferred, env: env, module_name: module_name) let ret_resolved = ret_result.resolved let ret_diags = ret_result.diagnostics - let resolved_ret = if item.inferred == none { none } else { - match item.inferred.value { - Resolved { node: authored_ret } => - if authored_ret.children |> count > 0 { - Some { value: Resolved { node: Node { name: authored_ret.name, span: authored_ret.span, ident_span: authored_ret.ident_span, children: authored_ret.children, connective: authored_ret.connective, params: authored_ret.params, inferred: Some { value: Resolved { node: ret_resolved } }, return_cardinality: authored_ret.return_cardinality, uses: authored_ret.uses, body: authored_ret.body, transport: authored_ret.transport, properties: ret_resolved.properties, type_annotation: authored_ret.type_annotation, is_self_recursive: authored_ret.is_self_recursive, has_non_tail_self_call: authored_ret.has_non_tail_self_call, match_pattern: authored_ret.match_pattern, expr_data: authored_ret.expr_data } } } - } else { - Some { value: Resolved { node: ret_resolved } } - } - _ => Some { value: Resolved { node: ret_resolved } } - } - } + let resolved_ret = if item.inferred == none { none } else { Some { value: Resolved { node: ret_resolved } } } let use_results = map(item.uses, u => resolve_resource_use(ru: u, env: env, module_name: module_name)) let resolved_uses = map(use_results, ur => ur.resource_use) @@ -932,14 +907,7 @@ fn resolve_item_types(item: Node, env: TypeEnv, module_name: String) -> ItemResu } else { resolve_node(n: item.type_annotation.value, env: env, module_name: module_name) } - let resolved_anno = if item.type_annotation == none { none } else { - let authored_anno = item.type_annotation.value - if authored_anno.children |> count > 0 { - Some { value: Node { name: authored_anno.name, span: authored_anno.span, ident_span: authored_anno.ident_span, children: authored_anno.children, connective: authored_anno.connective, params: authored_anno.params, inferred: Some { value: Resolved { node: anno_resolved.resolved } }, return_cardinality: authored_anno.return_cardinality, uses: authored_anno.uses, body: authored_anno.body, transport: authored_anno.transport, properties: anno_resolved.resolved.properties, type_annotation: authored_anno.type_annotation, is_self_recursive: authored_anno.is_self_recursive, has_non_tail_self_call: authored_anno.has_non_tail_self_call, match_pattern: authored_anno.match_pattern, expr_data: authored_anno.expr_data } } - } else { - Some { value: anno_resolved.resolved } - } - } + let resolved_anno = if item.type_annotation == none { none } else { Some { value: anno_resolved.resolved } } let anno_diags = anno_resolved.diagnostics let transport_resolved = if item.transport == none { diff --git a/src/v2/05_emit_rust.dag b/src/v2/05_emit_rust.dag index 684fced5d6a..6ff453fc373 100644 --- a/src/v2/05_emit_rust.dag +++ b/src/v2/05_emit_rust.dag @@ -197,15 +197,7 @@ fn rust_type_is_rc_wrapped(type_name: String) -> Bool { fn render_rust_applied_type_arg(n: Node, generic_param_names: List, shared_types: Set, source_indices: Map) -> String { match n.inferred { Some { value: TypeVariable { id: tv } } => tv -<<<<<<< HEAD - _ => if n.connective == NoConnective && n.children |> count == 0 { - coerce_primitive_type(target: Rust, dag_name: authored_name_at(source_indices: source_indices, node: n)) - } else { - render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) - } -======= _ => render_rust_decl_type(n: n, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices) ->>>>>>> origin/main } } @@ -1719,39 +1711,11 @@ fn render_rust_type_with_applied_binding(n: Node, shared_types: Set, sou match find_property(props: n.properties, prop_name: "__applied_type_args", source_indices: source_indices) { Some { value: applied } => if applied.children |> count > 0 { -<<<<<<< HEAD - let rendered = render_rust_applied_type(n: applied, shared_types: shared_types, source_indices: source_indices) - let applied_name = authored_name_at(source_indices: source_indices, node: applied) - let resolved_is_wrapped = match n.inferred { - Some { value: Resolved { node: resolved } } => rust_type_is_rc_wrapped(type_name: render_rust_type(n: resolved, shared_types: shared_types, source_indices: source_indices)) - _ => false - } - if (set_contains(shared_types, applied_name) || resolved_is_wrapped) && !rust_type_is_rc_wrapped(type_name: rendered) { wrap_shared_type(target: Rust, inner: rendered) } - else { rendered } -======= render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, source_indices: source_indices) ->>>>>>> origin/main } else { render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) } - None => - match n.inferred { - Some { value: Resolved { node: resolved } } => - match find_property(props: resolved.properties, prop_name: "__applied_type_args", source_indices: source_indices) { - Some { value: applied } => - if applied.children |> count > 0 { - let rendered = render_rust_applied_type(n: applied, shared_types: shared_types, source_indices: source_indices) - let applied_name = authored_name_at(source_indices: source_indices, node: applied) - let resolved_is_wrapped = rust_type_is_rc_wrapped(type_name: render_rust_type(n: resolved, shared_types: shared_types, source_indices: source_indices)) - if (set_contains(shared_types, applied_name) || resolved_is_wrapped) && !rust_type_is_rc_wrapped(type_name: rendered) { wrap_shared_type(target: Rust, inner: rendered) } - else { rendered } - } else { - render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) - } - None => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) - } - _ => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) - } + None => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices) } } @@ -2247,7 +2211,7 @@ fn emit_func_params(params: List, uses: List, service_names: List, source_indices: Map) -> String { - concat(" -> Result<", render_rust_type_with_applied_binding(n: inferred, shared_types: shared_types, source_indices: source_indices), ", Box>") + concat(" -> Result<", render_rust_type(n: inferred, shared_types: shared_types, source_indices: source_indices), ", Box>") } // ========================================================================= @@ -2286,27 +2250,15 @@ fn render_rust_param_sig_type(param: Node, generic_param_names: List, sh fn emit_rust_param_type(n: Node, generic_param_names: List, shared_types: Set, source_indices: Map) -> String { if n.params |> count > 0 { -<<<<<<< HEAD - let param_types = n.params |> map(p => render_rust_type_with_applied_binding(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices)) - let param_str = param_types |> join(separator: ", ") - let ret_str = match n.inferred { - Some { value: Resolved { node: rt } } => render_rust_type_with_applied_binding(n: rt, shared_types: shared_types, source_indices: source_indices) -======= let param_types = n.params |> map(p => render_rust_fn_sig_type(n: param_node_type_expr(n: p), generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices)) let param_str = param_types |> join(separator: ", ") let ret_str = match n.inferred { Some { value: Resolved { node: rt } } => render_rust_fn_sig_type(n: rt, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices) ->>>>>>> origin/main _ => "()" } concat("impl Fn(", param_str, ") -> ", ret_str, " + Clone") } else { -<<<<<<< HEAD - let rendered = render_rust_type_with_applied_binding(n: n, shared_types: shared_types, source_indices: source_indices) - rendered -======= render_rust_fn_sig_type(n: n, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices) ->>>>>>> origin/main } } @@ -2321,13 +2273,8 @@ fn emit_param(param: Node, generic_param_names: List, shared_types: Set< concat(emit_ident(name: pname, target: Rust), rust_items().param_type_sep, ty) } -<<<<<<< HEAD -fn emit_inferred(inferred: Node, shared_types: Set, source_indices: Map) -> String { - concat(rust_items().return_arrow, render_rust_type_with_applied_binding(n: inferred, shared_types: shared_types, source_indices: source_indices)) -======= fn emit_inferred(inferred: Node, generic_param_names: List, shared_types: Set, source_indices: Map) -> String { concat(rust_items().return_arrow, render_rust_fn_sig_type(n: inferred, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices)) ->>>>>>> origin/main } fn needs_reference_node(n: Node, source_indices: Map) -> Bool { @@ -5989,9 +5936,6 @@ fn data_value_has_cross_refs(value: Node) -> Bool { } fn emit_data_def(name: String, type_node: Node, value: Node, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { -<<<<<<< HEAD - let raw_ty_str = render_rust_type_with_applied_binding(n: type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices) -======= let annotation_type_node = type_node let render_type_node = if annotation_type_node.children |> count > 0 { annotation_type_node @@ -6002,7 +5946,6 @@ fn emit_data_def(name: String, type_node: Node, value: Node, registry: Map>>>>>> origin/main let ty_str = if raw_ty_str == "BoundedLattice" || raw_ty_str == "Rc" { match field_value_by_name(record: value, field_name: "top", source_indices: scope.type_env.source_indices) { Some { value: top_value } => @@ -6058,7 +6001,7 @@ fn rust_nominal_identity_data_expr(type_node: Node, value: Node, source_indices: } 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_with_applied_binding(n: type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices) + let raw_ty_str = render_rust_type(n: type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices) let type_name = authored_name_at(source_indices: scope.type_env.source_indices, node: type_node) if type_name == "BoundedLattice" { match value.expr_data { diff --git a/src/v2/stage0/src/v2_compiler_emit_rust.rs b/src/v2/stage0/src/v2_compiler_emit_rust.rs index d917d4b4490..8cdf4216d90 100644 --- a/src/v2/stage0/src/v2_compiler_emit_rust.rs +++ b/src/v2/stage0/src/v2_compiler_emit_rust.rs @@ -238,22 +238,7 @@ pub fn render_rust_applied_type_arg( ) -> String { match n.inferred.clone().as_deref().cloned() { Some(InferredNode::TypeVariable { id: tv, .. }) => tv.clone(), -<<<<<<< HEAD - _ => { - if ((n.connective.clone() == Connective::NoConnective) - && ((n.children.clone().len() as i64) == 0)) - { - coerce_primitive_type( - RenderTarget::Rust, - authored_name_at(source_indices, n.clone()), - ) - } else { - render_rust_type(n.clone(), shared_types, source_indices) - } - } -======= _ => render_rust_decl_type(n.clone(), generic_param_names, shared_types, source_indices), ->>>>>>> origin/main } } @@ -3677,73 +3662,17 @@ pub fn render_rust_type_with_applied_binding( ) { Some(applied) => { if ((applied.children.clone().len() as i64) > 0) { -<<<<<<< HEAD - let rendered = render_rust_applied_type( - applied.clone(), - shared_types.clone(), - source_indices.clone(), - ); - let applied_name = authored_name_at(source_indices.clone(), applied.clone()); - let resolved_is_wrapped = match n.inferred.clone().as_deref().cloned() { - Some(Resolved { node: resolved, .. }) => rust_type_is_rc_wrapped( - render_rust_type(resolved, shared_types.clone(), source_indices.clone()), - ), - _ => false, - }; - if ((shared_types.contains(&applied_name) || resolved_is_wrapped) - && !rust_type_is_rc_wrapped(rendered.clone())) - { - wrap_shared_type(RenderTarget::Rust, rendered) - } else { - rendered - } -======= render_rust_applied_type_shared( applied.clone(), Rc::new(vec![]), shared_types, source_indices.clone(), ) ->>>>>>> origin/main } else { render_rust_type(n.clone(), shared_types, source_indices.clone()) } } - None => match n.inferred.clone().as_deref().cloned() { - Some(Resolved { node: resolved, .. }) => match find_property( - resolved.properties.clone(), - "__applied_type_args".to_string(), - source_indices.clone(), - ) { - Some(applied) => { - if ((applied.children.clone().len() as i64) > 0) { - let rendered = render_rust_applied_type( - applied.clone(), - shared_types.clone(), - source_indices.clone(), - ); - let applied_name = - authored_name_at(source_indices.clone(), applied.clone()); - let resolved_is_wrapped = rust_type_is_rc_wrapped(render_rust_type( - resolved, - shared_types.clone(), - source_indices.clone(), - )); - if ((shared_types.contains(&applied_name) || resolved_is_wrapped) - && !rust_type_is_rc_wrapped(rendered.clone())) - { - wrap_shared_type(RenderTarget::Rust, rendered) - } else { - rendered - } - } else { - render_rust_type(n.clone(), shared_types, source_indices.clone()) - } - } - None => render_rust_type(n.clone(), shared_types, source_indices.clone()), - }, - _ => render_rust_type(n.clone(), shared_types, source_indices.clone()), - }, + None => render_rust_type(n.clone(), shared_types, source_indices.clone()), } } @@ -5540,7 +5469,7 @@ pub fn emit_func_inferred( v2_rt::concat( v2_rt::concat( " -> Result<".to_string(), - render_rust_type_with_applied_binding(inferred, shared_types, source_indices), + render_rust_type(inferred, shared_types, source_indices), ), ", Box>".to_string(), ) @@ -5582,11 +5511,7 @@ pub fn emit_rust_param_type( let param_types = Rc::new({ let mut __result = Vec::new(); for p in n.params.clone().iter().cloned() { -<<<<<<< HEAD - __result.push(render_rust_type_with_applied_binding( -======= __result.push(render_rust_fn_sig_type( ->>>>>>> origin/main param_node_type_expr(p.clone()), generic_param_names.clone(), shared_types.clone(), @@ -5597,22 +5522,12 @@ pub fn emit_rust_param_type( }); let param_str = param_types.join(&", ".to_string()); let ret_str = match n.inferred.clone().as_deref().cloned() { -<<<<<<< HEAD - Some(InferredNode::Resolved { node: rt, .. }) => { - render_rust_type_with_applied_binding( - rt.clone(), - shared_types.clone(), - source_indices.clone(), - ) - } -======= Some(InferredNode::Resolved { node: rt, .. }) => render_rust_fn_sig_type( rt.clone(), generic_param_names.clone(), shared_types.clone(), source_indices.clone(), ), ->>>>>>> origin/main _ => "()".to_string(), }; v2_rt::concat( @@ -5627,23 +5542,12 @@ pub fn emit_rust_param_type( ) } } else { -<<<<<<< HEAD - { - let rendered = render_rust_type_with_applied_binding( - n.clone(), - shared_types.clone(), - source_indices.clone(), - ); - rendered - } -======= render_rust_fn_sig_type( n.clone(), generic_param_names.clone(), shared_types.clone(), source_indices.clone(), ) ->>>>>>> origin/main } } @@ -5690,11 +5594,7 @@ pub fn emit_inferred( ) -> String { v2_rt::concat( rust_items().return_arrow.clone(), -<<<<<<< HEAD - render_rust_type_with_applied_binding(inferred, shared_types, source_indices), -======= render_rust_fn_sig_type(inferred, generic_param_names, shared_types, source_indices), ->>>>>>> origin/main ) } @@ -16626,10 +16526,6 @@ pub fn emit_data_def( emit_info: Rc, ) -> String { { -<<<<<<< HEAD - let raw_ty_str = render_rust_type_with_applied_binding( - type_node.clone(), -======= let annotation_type_node = type_node.clone(); let render_type_node = if ((annotation_type_node.children.clone().len() as i64) > 0) { annotation_type_node.clone() @@ -16641,7 +16537,6 @@ pub fn emit_data_def( }; let raw_ty_str = render_rust_type_with_applied_binding( render_type_node, ->>>>>>> origin/main shared_types.clone(), scope.type_env.clone().source_indices.clone(), ); @@ -16808,7 +16703,7 @@ pub fn emit_data_def_body( needs_rc: bool, ) -> String { { - let raw_ty_str = render_rust_type_with_applied_binding( + let raw_ty_str = render_rust_type( type_node.clone(), shared_types.clone(), scope.type_env.clone().source_indices.clone(), diff --git a/src/v2/stage0/src/v2_compiler_infer_resolve.rs b/src/v2/stage0/src/v2_compiler_infer_resolve.rs index 1af8a22042e..5ea35a9605e 100644 --- a/src/v2/stage0/src/v2_compiler_infer_resolve.rs +++ b/src/v2/stage0/src/v2_compiler_infer_resolve.rs @@ -731,36 +731,6 @@ pub fn resolve_node_bounded( } __result }); -<<<<<<< HEAD -======= - let applied_type_args = Rc::new(Node { - name: type_name.clone(), - span: n.span.clone(), - ident_span: n.ident_span.clone(), - children: resolved_args.clone(), - connective: Connective::NoConnective, - params: Rc::new(vec![]), - inferred: None, - return_cardinality: n.return_cardinality.clone(), - uses: Rc::new(vec![]), - body: None, - transport: None, - properties: Rc::new(vec![]), - type_annotation: None, - is_self_recursive: false, - has_non_tail_self_call: false, - match_pattern: None, - expr_data: Rc::new(ExprData::NoExprData), - ident: None, - }); - let applied_prop_span = kernel_span("__applied_type_args".to_string()); - let applied_type_args_property = make_field_init_node( - "__applied_type_args".to_string(), - applied_type_args, - n.span.clone(), - applied_prop_span, - ); ->>>>>>> origin/main let slot_bindings = Rc::new( decl.params .clone() @@ -1444,17 +1414,9 @@ pub fn resolve_param(param: Rc, env: Rc, module_name: String) -> Rc::new(ParamResult { param: make_resolved_param_node( param_node_name_at(param.clone(), env.source_indices.clone()), -<<<<<<< HEAD rendered_type, - match default_resolved.clone() { - Some(result) => Some(result.expr.clone()), - None => None, - }, -======= - type_resolved.clone(), default_expr, v2_rt::concat(param.properties.clone(), type_resolved.properties.clone()), ->>>>>>> origin/main param.span.clone(), node_name_span(param.clone()), ), @@ -2790,41 +2752,7 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) let resolved_ret = if (item.inferred.clone() == None) { None } else { - match item.inferred.clone().unwrap().as_ref().clone() { - InferredNode::Resolved { - node: authored_ret, .. - } => { - if ((authored_ret.children.clone().len() as i64) > 0) { - Some(Rc::new(InferredNode::Resolved { - node: Rc::new(Node { - name: authored_ret.name.clone(), - span: authored_ret.span.clone(), - ident_span: authored_ret.ident_span.clone(), - children: authored_ret.children.clone(), - connective: authored_ret.connective.clone(), - params: authored_ret.params.clone(), - inferred: Some(Rc::new(Resolved { - node: ret_resolved.clone(), - })), - return_cardinality: authored_ret.return_cardinality.clone(), - uses: authored_ret.uses.clone(), - body: authored_ret.body.clone(), - transport: authored_ret.transport.clone(), - properties: ret_resolved.properties.clone(), - type_annotation: authored_ret.type_annotation.clone(), - is_self_recursive: authored_ret.is_self_recursive, - has_non_tail_self_call: authored_ret.has_non_tail_self_call.clone(), - match_pattern: authored_ret.match_pattern.clone(), - expr_data: authored_ret.expr_data.clone(), - ident: None, - }), - })) - } else { - Some(Rc::new(InferredNode::Resolved { node: ret_resolved })) - } - } - _ => Some(Rc::new(InferredNode::Resolved { node: ret_resolved })), - } + Some(Rc::new(InferredNode::Resolved { node: ret_resolved })) }; let use_results = Rc::new({ let mut __result = Vec::new(); @@ -2888,35 +2816,7 @@ pub fn resolve_item_types(item: Rc, env: Rc, module_name: String) let resolved_anno = if (item.type_annotation.clone() == None) { None } else { - { - let authored_anno = item.type_annotation.clone().unwrap(); - if ((authored_anno.children.clone().len() as i64) > 0) { - Some(Rc::new(Node { - name: authored_anno.name.clone(), - span: authored_anno.span.clone(), - ident_span: authored_anno.ident_span.clone(), - children: authored_anno.children.clone(), - connective: authored_anno.connective.clone(), - params: authored_anno.params.clone(), - inferred: Some(Rc::new(Resolved { - node: anno_resolved.resolved.clone(), - })), - return_cardinality: authored_anno.return_cardinality.clone(), - uses: authored_anno.uses.clone(), - body: authored_anno.body.clone(), - transport: authored_anno.transport.clone(), - properties: anno_resolved.resolved.clone().properties.clone(), - type_annotation: authored_anno.type_annotation.clone(), - is_self_recursive: authored_anno.is_self_recursive, - has_non_tail_self_call: authored_anno.has_non_tail_self_call.clone(), - match_pattern: authored_anno.match_pattern.clone(), - expr_data: authored_anno.expr_data.clone(), - ident: None, - })) - } else { - Some(anno_resolved.resolved.clone()) - } - } + Some(anno_resolved.resolved.clone()) }; let anno_diags = anno_resolved.diagnostics.clone(); let transport_resolved = if (item.transport.clone() == None) { diff --git a/src/v2/tests/src/pipeline.rs b/src/v2/tests/src/pipeline.rs index aabda91b15c..94140cf402d 100644 --- a/src/v2/tests/src/pipeline.rs +++ b/src/v2/tests/src/pipeline.rs @@ -5266,72 +5266,6 @@ type Outer { ); } -#[test] -fn generic_annotation_preserves_type_args_without_name_keyed_carrier_patch() { - let source = r#" -module test_generic_annotation_preservation - -type Node { - label: String -} - -type RuntimeValue { - text: String -} - -type Wrapper { - value: T -} - -type ProbeClaimRun { - subject: S - actual: A -} - -data cached_probe_run: ProbeClaimRun, RuntimeValue> = ProbeClaimRun { - subject: Wrapper { value: Node { label: "n" } } - actual: RuntimeValue { text: "rv" } -} - -fn probe_param(run: ProbeClaimRun, RuntimeValue>) -> Int { - 1 -} - -fn probe_return() -> ProbeClaimRun, RuntimeValue> { - ProbeClaimRun { - subject: Wrapper { value: Node { label: "return" } } - actual: RuntimeValue { text: "rv" } - } -} -"#; - let result = compile_dag(source); - assert_no_diagnostics(&result); - let content = find_file(&result, "src/test_generic_annotation_preservation.rs"); - assert!( - content.contains( - "pub fn cached_probe_run() -> Rc, RuntimeValue>>" - ), - "generic data cache return type should preserve applied type args, got:\n{}", - content - ); - assert!( - content - .contains("pub fn probe_param(run: ProbeClaimRun, RuntimeValue>) -> i64"), - "generic function parameter should preserve applied type args, got:\n{}", - content - ); - assert!( - content.contains("pub fn probe_return() -> ProbeClaimRun, RuntimeValue>"), - "generic function return should preserve applied type args, got:\n{}", - content - ); - assert!( - !content.contains("ProbeClaimRun>"), - "generic carrier must not be emitted bare, got:\n{}", - content - ); -} - // ── Targeted type rendering correctness tests ───────────────────────── fn test_leaf_node(name: &str) -> Rc { From 04483f83a6d03b333de6123ea2cc43e7556b58e5 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 15:25:16 +0000 Subject: [PATCH 15/19] =?UTF-8?q?WIP:=20=C2=A710.0=20worksheet:=20TestClai?= =?UTF-8?q?mRun=20generic=20preservation=20in=20v2=20Rust=20emit=20(E010?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v2/04_lookup.dag | 7 ++++++- src/v2/04_patterns.dag | 5 +++++ src/v2/04_resolve.dag | 2 +- src/v2/stage0/src/v2_compiler_infer_lookup.rs | 12 +++++++++++- src/v2/stage0/src/v2_compiler_infer_patterns.rs | 10 ++++++++++ src/v2/stage0/src/v2_compiler_infer_resolve.rs | 2 +- 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/v2/04_lookup.dag b/src/v2/04_lookup.dag index d7f3f1ff374..af3a54239c1 100644 --- a/src/v2/04_lookup.dag +++ b/src/v2/04_lookup.dag @@ -140,7 +140,12 @@ fn resolve_scrutinee_type_node_seen(env: TypeEnv, n: Node, seen: Map count == 0 { + if normed.connective == NoConnective && normed.children |> count > 0 && normed.inferred != none { + match normed.inferred { + Some { value: Resolved { node: target } } => resolve_scrutinee_type_node_seen(env: env, n: target, seen: seen) + _ => normed + } + } else if normed.connective == NoConnective && normed.children |> count == 0 { let canonical = authored_name(env: env, node: normed) if normed.inferred != none { let next_seen = if canonical == "" { seen } else { map_insert(seen, canonical, true) } diff --git a/src/v2/04_patterns.dag b/src/v2/04_patterns.dag index 881fc8b381e..98bba723f06 100644 --- a/src/v2/04_patterns.dag +++ b/src/v2/04_patterns.dag @@ -75,6 +75,11 @@ fn pattern_subject_from_node(n: Node) -> PatternSubject { let is_error = if n.inferred != none { is_compiler_error(inferred: n.inferred.value) } else { false } if is_error { PatternLookupBlocked + } else if n.connective == NoConnective && n.children |> count > 0 && n.inferred != none { + match n.inferred { + Some { value: Resolved { node: target } } => pattern_subject_from_node(n: target) + _ => PatternResolved { node: n } + } } else { PatternResolved { node: n } } diff --git a/src/v2/04_resolve.dag b/src/v2/04_resolve.dag index a61320eb286..500c7fa2847 100644 --- a/src/v2/04_resolve.dag +++ b/src/v2/04_resolve.dag @@ -320,7 +320,7 @@ fn resolve_node_bounded(n: Node, env: TypeEnv, module_name: String, depth: Int) } let target_result = resolve_node_bounded(n: alias_target, env: env, module_name: module_name, depth: depth + 1) let is_recursive = is_recursive_type_by_name(env: env, name: type_name) - let expanded_node = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: target_result.resolved.children, connective: target_result.resolved.connective, params: [], inferred: n.inferred, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: target_result.resolved.properties, type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data } + let expanded_node = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: target_result.resolved.children, connective: target_result.resolved.connective, params: [], inferred: target_result.resolved.inferred, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: target_result.resolved.properties, type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data } let resolved_node = Node { name: type_name, span: n.span, ident_span: n.ident_span, children: resolved_args, connective: NoConnective, params: [], inferred: Some { value: Resolved { node: expanded_node } }, return_cardinality: n.return_cardinality, uses: n.uses, body: n.body, transport: n.transport, properties: target_result.resolved.properties, type_annotation: n.type_annotation, is_self_recursive: is_recursive, has_non_tail_self_call: n.has_non_tail_self_call, match_pattern: n.match_pattern, expr_data: n.expr_data } NodeResolveResult { resolved: resolved_node, diagnostics: concat(arity_diags, arg_diags, target_result.diagnostics) } } else { diff --git a/src/v2/stage0/src/v2_compiler_infer_lookup.rs b/src/v2/stage0/src/v2_compiler_infer_lookup.rs index c2b27a8315b..27224842e8a 100644 --- a/src/v2/stage0/src/v2_compiler_infer_lookup.rs +++ b/src/v2/stage0/src/v2_compiler_infer_lookup.rs @@ -172,7 +172,17 @@ pub fn resolve_scrutinee_type_node_seen( return n.clone(); } let normed = normalize_access_type_node(n.clone()); - if ((normed.connective.clone() == Connective::NoConnective) + if (((normed.connective.clone() == Connective::NoConnective) + && ((normed.children.clone().len() as i64) > 0)) + && (normed.inferred.clone() != None)) + { + match normed.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: target, .. }) => { + resolve_scrutinee_type_node_seen(env.clone(), target.clone(), seen) + } + _ => normed.clone(), + } + } else if ((normed.connective.clone() == Connective::NoConnective) && ((normed.children.clone().len() as i64) == 0)) { { diff --git a/src/v2/stage0/src/v2_compiler_infer_patterns.rs b/src/v2/stage0/src/v2_compiler_infer_patterns.rs index 331b9b906d8..b1b0124fbb7 100644 --- a/src/v2/stage0/src/v2_compiler_infer_patterns.rs +++ b/src/v2/stage0/src/v2_compiler_infer_patterns.rs @@ -120,6 +120,16 @@ pub fn pattern_subject_from_node(n: Rc) -> Rc { }; if is_error { Rc::new(PatternSubject::PatternLookupBlocked) + } else if (((n.connective.clone() == Connective::NoConnective) + && ((n.children.clone().len() as i64) > 0)) + && (n.inferred.clone() != None)) + { + match n.inferred.clone().as_deref().cloned() { + Some(InferredNode::Resolved { node: target, .. }) => { + pattern_subject_from_node(target.clone()) + } + _ => Rc::new(PatternSubject::PatternResolved { node: n.clone() }), + } } else { Rc::new(PatternSubject::PatternResolved { node: n.clone() }) } diff --git a/src/v2/stage0/src/v2_compiler_infer_resolve.rs b/src/v2/stage0/src/v2_compiler_infer_resolve.rs index 5ea35a9605e..ae00b838a07 100644 --- a/src/v2/stage0/src/v2_compiler_infer_resolve.rs +++ b/src/v2/stage0/src/v2_compiler_infer_resolve.rs @@ -820,7 +820,7 @@ pub fn resolve_node_bounded( children: target_result.resolved.clone().children.clone(), connective: target_result.resolved.clone().connective.clone(), params: Rc::new(vec![]), - inferred: n.inferred.clone(), + inferred: target_result.resolved.clone().inferred.clone(), return_cardinality: n.return_cardinality.clone(), uses: n.uses.clone(), body: n.body.clone(), From 86283053c4a009331ed11361795da728956d9cf4 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 16:16:09 +0000 Subject: [PATCH 16/19] Preserve resolved generic param children --- src/v2/04_resolve.dag | 2 +- src/v2/stage0/src/v2_compiler_infer_resolve.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v2/04_resolve.dag b/src/v2/04_resolve.dag index 500c7fa2847..aabe122b59f 100644 --- a/src/v2/04_resolve.dag +++ b/src/v2/04_resolve.dag @@ -494,7 +494,7 @@ fn resolve_param(param: Node, env: TypeEnv, module_name: String) -> ParamResult let type_result = resolve_node(n: authored_type, env: env, module_name: module_name) let type_resolved = type_result.resolved let rendered_type = if authored_type.children |> count > 0 { - Node { name: authored_type.name, span: authored_type.span, ident_span: authored_type.ident_span, children: authored_type.children, connective: authored_type.connective, params: authored_type.params, inferred: Some { value: Resolved { node: type_resolved } }, return_cardinality: authored_type.return_cardinality, uses: authored_type.uses, body: authored_type.body, transport: authored_type.transport, properties: type_resolved.properties, type_annotation: authored_type.type_annotation, is_self_recursive: authored_type.is_self_recursive, has_non_tail_self_call: authored_type.has_non_tail_self_call, match_pattern: authored_type.match_pattern, expr_data: authored_type.expr_data } + Node { name: authored_type.name, span: authored_type.span, ident_span: authored_type.ident_span, children: type_resolved.children, connective: authored_type.connective, params: authored_type.params, inferred: Some { value: Resolved { node: type_resolved } }, return_cardinality: authored_type.return_cardinality, uses: authored_type.uses, body: authored_type.body, transport: authored_type.transport, properties: type_resolved.properties, type_annotation: authored_type.type_annotation, is_self_recursive: authored_type.is_self_recursive, has_non_tail_self_call: authored_type.has_non_tail_self_call, match_pattern: authored_type.match_pattern, expr_data: authored_type.expr_data } } else { type_resolved } diff --git a/src/v2/stage0/src/v2_compiler_infer_resolve.rs b/src/v2/stage0/src/v2_compiler_infer_resolve.rs index ae00b838a07..2a9daabecd4 100644 --- a/src/v2/stage0/src/v2_compiler_infer_resolve.rs +++ b/src/v2/stage0/src/v2_compiler_infer_resolve.rs @@ -1366,7 +1366,7 @@ pub fn resolve_param(param: Rc, env: Rc, module_name: String) -> name: authored_type.name.clone(), span: authored_type.span.clone(), ident_span: authored_type.ident_span.clone(), - children: authored_type.children.clone(), + children: type_resolved.children.clone(), connective: authored_type.connective.clone(), params: authored_type.params.clone(), inferred: Some(Rc::new(Resolved { From cf09922d770d97e65c30cac98a64c15db8d748dd Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 17:40:22 +0000 Subject: [PATCH 17/19] =?UTF-8?q?WIP:=20Caretake=20#4182=20TestClaimRun=20?= =?UTF-8?q?E0107=20PR=20=E2=80=94=20hold/recheck=20after=20source=5Fatom?= =?UTF-8?q?=5Fst?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/std/target_model.dag | 103 +++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 24 deletions(-) diff --git a/src/v4/std/target_model.dag b/src/v4/std/target_model.dag index 132beea6020..f89d4fde287 100644 --- a/src/v4/std/target_model.dag +++ b/src/v4/std/target_model.dag @@ -48,10 +48,12 @@ import v4.std.node { Instantiation, Named, Node, + NodeFold, Positional, Symbol, TypeNode, - content_hash + content_hash, + fold_node } import v4.std.node_query { find_named_child, node_positional_child_targets } import v4.std.logic { Bool } @@ -219,37 +221,90 @@ fn source_atom_char_projection_from_node(source: Node) -> Optional Optional>` (or -// `Node -> Optional`) projection over `free_monoid_type_node`'s encoded surface; replace -// this local encoded-node projection with that accessor. The local recursion is fail-closed and -// bounded to TS-ATOM-REALIZATION's String value-template bridge; forbidden: adding another -// FreeMonoid storage walker outside this receipt. -fn source_atom_string_projection_from_node(source: Node) -> Optional { +type SourceAtomStringProjectionFold + = SourceAtomStringFoldInit + | SourceAtomStringFoldHeadSeen + | SourceAtomStringFoldTailSeen + | SourceAtomStringFoldChar + | SourceAtomStringFoldString + | SourceAtomStringFoldInvalid + +fn source_atom_string_projection_fold_init(source: Node) -> SourceAtomStringProjectionFold { match source.kind { TypeNode { connective: Atom { identity: id } } => if id == free_monoid_variant_empty { - optional_present(source_atom_string(value: source)) + SourceAtomStringFoldString } else { - optional_absent() + match source_atom_char_projection_from_node(source: source) { + Present { value: _ } => SourceAtomStringFoldChar + Absent => SourceAtomStringFoldInvalid + } } TypeNode { connective: Conj } => - match find_named_child(root: source, name: free_monoid_field_head) { - Accepted { value: head } => - match find_named_child(root: source, name: free_monoid_field_tail) { - Accepted { value: tail } => - match source_atom_char_projection_from_node(source: head) { - Present { value: _ } => - match source_atom_string_projection_from_node(source: tail) { - Present { value: _ } => optional_present(source_atom_string(value: source)) - Absent => optional_absent() - } - Absent => optional_absent() - } - Rejected { diagnostics: _ } => optional_absent() + if count(source.children) == 2 { + SourceAtomStringFoldInit + } else { + SourceAtomStringFoldInvalid + } + _ => SourceAtomStringFoldInvalid + } +} + +fn source_atom_string_projection_fold_step( + acc: SourceAtomStringProjectionFold, + edge: Edge, + child: SourceAtomStringProjectionFold +) -> SourceAtomStringProjectionFold { + match acc { + SourceAtomStringFoldInvalid => SourceAtomStringFoldInvalid + SourceAtomStringFoldString => SourceAtomStringFoldInvalid + SourceAtomStringFoldChar => SourceAtomStringFoldInvalid + _ => + match edge.label { + Named { name: ename } => + if ename == free_monoid_field_head { + match child { + SourceAtomStringFoldChar => + match acc { + SourceAtomStringFoldInit => SourceAtomStringFoldHeadSeen + SourceAtomStringFoldTailSeen => SourceAtomStringFoldString + _ => SourceAtomStringFoldInvalid + } + _ => SourceAtomStringFoldInvalid + } + } else if ename == free_monoid_field_tail { + match child { + SourceAtomStringFoldString => + match acc { + SourceAtomStringFoldInit => SourceAtomStringFoldTailSeen + SourceAtomStringFoldHeadSeen => SourceAtomStringFoldString + _ => SourceAtomStringFoldInvalid + } + _ => SourceAtomStringFoldInvalid + } + } else { + SourceAtomStringFoldInvalid } - Rejected { diagnostics: _ } => optional_absent() + _ => SourceAtomStringFoldInvalid } + } +} + +// 🟡 gated — feature:free-monoid-node-projection — owner:Modeling DFS / std.algebra lane — +// dissolve-on: std.algebra exports a canonical `Node -> Optional>` (or +// `Node -> Optional`) projection over `free_monoid_type_node`'s encoded surface; replace +// this local encoded-node projection with that accessor. The local recursion is fail-closed and +// bounded to TS-ATOM-REALIZATION's String value-template bridge; forbidden: adding another +// FreeMonoid storage walker outside this receipt. +fn source_atom_string_projection_from_node(source: Node) -> Optional { + match fold_node( + n: source, + algebra: NodeFold { + init: source_atom_string_projection_fold_init, + step: source_atom_string_projection_fold_step + } + ) { + SourceAtomStringFoldString => optional_present(source_atom_string(value: source)) _ => optional_absent() } } From 8f2c4629efb279392497547e3d7be164dd2dd58b Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 18:40:27 +0000 Subject: [PATCH 18/19] Classify source atom string fold state --- src/v4/std/target_model.dag | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/v4/std/target_model.dag b/src/v4/std/target_model.dag index f89d4fde287..934ba2d0f76 100644 --- a/src/v4/std/target_model.dag +++ b/src/v4/std/target_model.dag @@ -221,6 +221,9 @@ fn source_atom_char_projection_from_node(source: Node) -> Optional +// projection; dissolve-on: std.algebra exports the canonical string/free-monoid projection +// named by the `free-monoid-node-projection` receipt below. type SourceAtomStringProjectionFold = SourceAtomStringFoldInit | SourceAtomStringFoldHeadSeen From 52cf6f5de60566108da2acd08009405c52c2d34b Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 1 Jun 2026 20:16:57 +0000 Subject: [PATCH 19/19] =?UTF-8?q?WIP:=20Caretake=20#4182=20TestClaimRun=20?= =?UTF-8?q?E0107=20PR=20=E2=80=94=20hold/recheck=20after=20source=5Fatom?= =?UTF-8?q?=5Fst?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dsl/gunbc/ci_github_actions_workflow.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsl/gunbc/ci_github_actions_workflow.dag b/dsl/gunbc/ci_github_actions_workflow.dag index 793b870cbd6..0ec9810ae87 100644 --- a/dsl/gunbc/ci_github_actions_workflow.dag +++ b/dsl/gunbc/ci_github_actions_workflow.dag @@ -103,6 +103,7 @@ data gunbc_ci_github_actions_workflow: Workflow = { }, { id: "affected", name: none, + continue_on_error: true, runner: SelfHosted { labels: ["self-hosted", "linux", "arm64"] }, steps: [RunStep { name: Some { value: "Isolate toolchain dirs (srv1/srv2 shared-$HOME concurrent-rustup race)" }, @@ -179,7 +180,6 @@ data gunbc_ci_github_actions_workflow: Workflow = { if_condition: Some { value: "github.event.pull_request.draft != true" }, strategy: none, timeout_minutes: Some { value: 15 }, - continue_on_error: true, concurrency: none }, { id: "ci_floor",