From 284de2e8262a138b373bc58073b6392b93a02179 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sat, 3 Oct 2026 19:54:31 +0000 Subject: [PATCH 1/6] Emitter: an effectful fold step is realized as a loop in the enclosing async frame Fold handed its step to Iterator::fold as a synchronous closure, so an effectful callee's `.await?` landed inside it (rustc E0728). The step now runs as a `for` loop over a mutable accumulator when it reaches an awaited call, asked of the same two authorities that write the await (item_is_effectful_callee and is_typed_service_call_receiver). Pure folds keep the closure realization. Control: src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs emits, rustc- compiles and runs an effectful fold with a record accumulator (RED before, green after). Stage0 mirror via claim_executor --required-regen; second pass is a fixed point. Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/05_emit_rust.dag | 98 +++++++- src/v1/stage0/src/v1_compiler_emit_rust.rs | 212 +++++++++++++++--- .../tests/effectful_fold_step_emitted_rust.rs | 176 +++++++++++++++ 3 files changed, 442 insertions(+), 44 deletions(-) create mode 100644 src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 116c353942b..441e5ae319f 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -12622,6 +12622,12 @@ fn emit_typed_collection_lambda(lambda_expr: Node, elem_type_str: String, regist } } +// A unit-element accumulator rendering is an inference gap, not a type, so both fold realizations +// leave it to the target's inference rather than annotate it. +fn rust_fold_safe_acc_type(acc_type_str: String) -> String { + if acc_type_str == "Rc>" || acc_type_str == "Vec<()>" || acc_type_str == "Option<()>" { "_" } else { acc_type_str } +} + fn emit_typed_fold_lambda(lambda_expr: Node, acc_type_str: String, elem_type_str: String, elem_borrowed: Bool, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { match lambda_expr.expr_data { ExprLambda => @@ -12629,7 +12635,7 @@ fn emit_typed_fold_lambda(lambda_expr: Node, acc_type_str: String, elem_type_str let bd = lambda_body(texpr: lambda_expr) let pn = lambda_expr.children |> skip(1) - let safe_acc_type = if acc_type_str == "Rc>" || acc_type_str == "Vec<()>" || acc_type_str == "Option<()>" { "_" } else { acc_type_str } + let safe_acc_type = rust_fold_safe_acc_type(acc_type_str: acc_type_str) let fallback_types = ps |> enumerate |> map(pair => if pair.first == 0 { safe_acc_type } else { elem_type_str } ) @@ -12840,13 +12846,91 @@ fn emit_rust_fold_method_call(method_call_node: Node, fold_accumulator_type: Nod Present { value: a } => fold_lambda_element_unused(lambda_expr: arg_value(n: a), source_indices: scope.type_env.source_indices) Absent => false } - let fold_fn = match args |> skip(1) |> first { - Present { value: a } => - emit_typed_fold_lambda(lambda_expr: arg_value(n: a), acc_type_str: lambda_acc_type_str, elem_type_str: fold_elem_type_str, elem_borrowed: elem_unused, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: fold_emit_info) - Absent => "compile_error!(\"missing fold function argument\")" - } let iter_template = if elem_unused { replace(sharing.iter_owned, ".cloned()", "") } else { sharing.iter_owned } - concat(apply_type_template1(template: iter_template, arg0: recv_str), ".fold(", init_str, ", ", fold_fn, ")") + let iter_str = apply_type_template1(template: iter_template, arg0: recv_str) + let step_awaits = match args |> skip(1) |> first { + Present { value: a } => rust_expr_reaches_awaited_call(n: arg_value(n: a), registry: registry, source_indices: scope.type_env.source_indices) + Absent => false + } + if step_awaits { + emit_rust_effectful_fold_loop(lambda_expr: fold_lambda_node, iter_str: iter_str, init_str: init_str, acc_type_str: lambda_acc_type_str, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: fold_emit_info) + } else { + let fold_fn = match args |> skip(1) |> first { + Present { value: a } => + emit_typed_fold_lambda(lambda_expr: arg_value(n: a), acc_type_str: lambda_acc_type_str, elem_type_str: fold_elem_type_str, elem_borrowed: elem_unused, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: fold_emit_info) + Absent => "compile_error!(\"missing fold function argument\")" + } + concat(iter_str, ".fold(", init_str, ", ", fold_fn, ")") + } +} + +// A FOLD IS A BOUNDED LOOP, AND `Iterator::fold` IS ONLY ONE REALIZATION OF IT -- THE ONE THAT +// PRESUMES A PURE STEP. The step is handed to fold as a closure, and a Rust closure is a separate, +// synchronous frame: an effectful callee inside it is emitted, by the one authority every call site +// asks (item_is_effectful_callee, and the typed service-call predicate), with `.await?`, which is +// E0728 in that frame (four sites on the approval broker's native closure, among them +// gunbc.auth.approval_decision_store pending_escalations). The closure is the wrong link, not the +// await: the enclosing fn is already async BECAUSE it reaches that effect, so the step belongs in +// the enclosing frame, where both the await and the `?` mean what they mean everywhere else in the +// fn -- the effect's refusal propagates out of the fold exactly as it would out of a let. That is +// the same move the tail-call lowering makes for effectful recursion (a loop over a mutable state +// slot in the caller's frame, not a recursive async call), applied to the Loop behavior fold +// already is. The step's parameters are bound as lets per element in declaration order, so the +// body is emitted by the ordinary expression emitter against the same lambda scope the closure +// realization uses; nothing about the body is re-derived here. +fn emit_rust_effectful_fold_loop(lambda_expr: Node, iter_str: String, init_str: String, acc_type_str: String, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { + match lambda_expr.expr_data { + ExprLambda => + let si = scope.type_env.source_indices + let ps = lambda_param_names_at(texpr: lambda_expr, source_indices: si) + let pn = lambda_expr.children |> skip(1) + let acc_param_type = rust_fold_safe_acc_type(acc_type_str: acc_type_str) + let acc_name = match ps |> first { Present { value: n } => n Absent => "_" } + let elem_name = match ps |> skip(1) |> first { Present { value: n } => n Absent => "_" } + let lambda_scope = lambda_scope_from_children(scope: scope, params: ps, param_nodes: pn) + let body_str = emit_typed_expr(texpr: lambda_body(texpr: lambda_expr), registry: registry, scope: lambda_scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024) + let acc_ident = if acc_name == "_" { "_" } else { emit_ident(name: acc_name, target: Rust) } + let elem_ident = if elem_name == "_" { "_" } else { emit_ident(name: elem_name, target: Rust) } + let acc_decl = if acc_param_type == "_" || acc_param_type == "" { "" } else { concat(": ", acc_param_type) } + let acc_unwrap = if acc_name != "_" && set_contains(emit_info.owned_bindings, acc_name) { + concat("let ", acc_ident, " = v1_rt::take_owned(", acc_ident, "); ") + } else { "" } + concat( + "{ let mut __fold_acc", acc_decl, " = ", init_str, "; ", + "for __fold_elem in ", iter_str, " { ", + "let ", acc_ident, " = __fold_acc; ", acc_unwrap, + "let ", elem_ident, " = __fold_elem; ", + "__fold_acc = { ", body_str, " }; ", + "} __fold_acc }" + ) + _ => emit_rust_compile_error_expr(message: "effectful fold step is not a lambda: an effectful function value has no synchronous closure realization and no loop realization") + } +} + +// DOES EMITTING THIS EXPRESSION PRODUCE AN `.await?` -- asked of the same two authorities that write +// one: a source call whose callee item_is_effectful_callee, and a service op through a receiver +// is_typed_service_call_receiver admits. Nested lambdas are walked too: an await anywhere inside the +// step forces the step into the async frame, and a nested fold realizes its own loop by this rule. +fn rust_expr_reaches_awaited_call(n: Node, registry: Map, source_indices: Map) -> Bool { + let here = match n.expr_data { + ExprCall { call_semantics: cs, descent_evidence: _ } => + match call_semantics_target(cs: cs) { + SourceDeclarationCall { owner_module_path: owner, decl_name: decl } => + match lookup_item_by_identity(registry: registry, id: DeclaredCallableIdentity { owner_module_path: owner, decl_name: decl }) { + Present { value: info } => item_is_effectful_callee(info: info) + Absent => false + } + _ => false + } + ExprMethodCall { method_semantics: ms } => + match ms { + Present { value: ServiceMethodSemantics { service_name: _, op_params: _ } } => + is_typed_service_call_receiver(receiver: method_receiver(texpr: n), source_indices: source_indices) + _ => false + } + _ => false + } + here || n.children |> any(c => rust_expr_reaches_awaited_call(n: c, registry: registry, source_indices: source_indices)) } fn fold_lambda_element_unused(lambda_expr: Node, source_indices: Map) -> Bool { diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 1ad1763fdcd..753ece5dd76 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -27135,6 +27135,17 @@ pub fn emit_typed_collection_lambda( } } +pub fn rust_fold_safe_acc_type(acc_type_str: String) -> String { + if (((acc_type_str.clone() == "Rc>".to_string()) + || (acc_type_str.clone() == "Vec<()>".to_string())) + || (acc_type_str.clone() == "Option<()>".to_string())) + { + "_".to_string() + } else { + acc_type_str.clone() + } +} + pub fn emit_typed_fold_lambda( lambda_expr: Rc, acc_type_str: String, @@ -27162,14 +27173,7 @@ pub fn emit_typed_fold_lambda( .skip(1 as usize) .collect::>(), ); - let safe_acc_type = if (((acc_type_str.clone() == "Rc>".to_string()) - || (acc_type_str.clone() == "Vec<()>".to_string())) - || (acc_type_str.clone() == "Option<()>".to_string())) - { - "_".to_string() - } else { - acc_type_str.clone() - }; + let safe_acc_type = rust_fold_safe_acc_type(acc_type_str.clone()); let fallback_types = Rc::new({ let mut __result = Vec::new(); for pair in Rc::new( @@ -27731,22 +27735,6 @@ pub fn emit_rust_fold_method_call( ), std::option::Option::None => false, }; - let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { - Some(a) => emit_typed_fold_lambda( - crate::v1_std_core::arg_value(a.clone()), - lambda_acc_type_str.clone(), - fold_elem_type_str.clone(), - elem_unused.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - fold_emit_info.clone(), - ), - std::option::Option::None => { - "compile_error!(\"missing fold function argument\")".to_string() - } - }; let iter_template = if elem_unused.clone() { v1_rt::replace( sharing.iter_owned.clone(), @@ -27756,28 +27744,178 @@ pub fn emit_rust_fold_method_call( } else { sharing.iter_owned.clone() }; - v1_rt::concat( - v1_rt::concat( + let iter_str = crate::v1_compiler_emit_core_support::apply_type_template1( + iter_template.clone(), + recv_str.clone(), + ); + let step_awaits = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => rust_expr_reaches_awaited_call( + crate::v1_std_core::arg_value(a.clone()), + registry.clone(), + scope.type_env.clone().source_indices.clone(), + ), + std::option::Option::None => false, + }; + if step_awaits.clone() { + emit_rust_effectful_fold_loop( + fold_lambda_node.clone(), + iter_str.clone(), + init_str.clone(), + lambda_acc_type_str.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ) + } else { + { + let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => emit_typed_fold_lambda( + crate::v1_std_core::arg_value(a.clone()), + lambda_acc_type_str.clone(), + fold_elem_type_str.clone(), + elem_unused.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ), + std::option::Option::None => { + "compile_error!(\"missing fold function argument\")".to_string() + } + }; v1_rt::concat( v1_rt::concat( v1_rt::concat( - crate::v1_compiler_emit_core_support::apply_type_template1( - iter_template.clone(), - recv_str.clone(), + v1_rt::concat( + v1_rt::concat(iter_str.clone(), ".fold(".to_string()), + init_str.clone(), ), - ".fold(".to_string(), + ", ".to_string(), ), - init_str.clone(), + fold_fn.clone(), ), - ", ".to_string(), - ), - fold_fn.clone(), - ), - ")".to_string(), - ) + ")".to_string(), + ) + } + } } } +pub fn emit_rust_effectful_fold_loop( + lambda_expr: Rc, + iter_str: String, + init_str: String, + acc_type_str: String, + registry: Rc>>, + scope: Rc, + depth: i64, + shared_types: Rc>, + emit_info: Rc, +) -> String { + match (*lambda_expr.expr_data.clone()).clone() { + ExprData::ExprLambda => { + let si = scope.type_env.clone().source_indices.clone(); +let ps = crate::v1_std_core::lambda_param_names_at(lambda_expr.clone(), si.clone()); +let pn = Rc::new(lambda_expr.children.clone().iter().cloned().skip(1 as usize).collect::>()); +let acc_param_type = rust_fold_safe_acc_type(acc_type_str.clone()); +let acc_name = match ps.clone().first().cloned() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let elem_name = match ps.clone().iter().cloned().skip(1 as usize).next() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let lambda_scope = lambda_scope_from_children(scope.clone(), ps.clone(), pn.clone()); +let body_str = emit_typed_expr(crate::v1_std_core::lambda_body(lambda_expr.clone()), registry.clone(), lambda_scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone(), 1024); +let acc_ident = if (acc_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(acc_name.clone(), RenderTarget::Rust) + }; +let elem_ident = if (elem_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(elem_name.clone(), RenderTarget::Rust) + }; +let acc_decl = if ((acc_param_type.clone() == "_".to_string()) || (acc_param_type.clone() == "".to_string())) { + "".to_string() + } else { + v1_rt::concat(": ".to_string(), acc_param_type.clone()) + }; +let acc_unwrap = if ((acc_name.clone() != "_".to_string()) && v1_rt::set_contains(&emit_info.owned_bindings.clone(), acc_name.clone())) { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("let ".to_string(), acc_ident.clone()), " = v1_rt::take_owned(".to_string()), acc_ident.clone()), "); ".to_string()) + } else { + "".to_string() + }; +v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("{ let mut __fold_acc".to_string(), acc_decl.clone()), " = ".to_string()), init_str.clone()), "; ".to_string()), "for __fold_elem in ".to_string()), iter_str.clone()), " { ".to_string()), "let ".to_string()), acc_ident.clone()), " = __fold_acc; ".to_string()), acc_unwrap.clone()), "let ".to_string()), elem_ident.clone()), " = __fold_elem; ".to_string()), "__fold_acc = { ".to_string()), body_str.clone()), " }; ".to_string()), "} __fold_acc }".to_string()) +}, + _ => emit_rust_compile_error_expr("effectful fold step is not a lambda: an effectful function value has no synchronous closure realization and no loop realization".to_string()), +} +} + +pub fn rust_expr_reaches_awaited_call( + n: Rc, + registry: Rc>>, + source_indices: Rc>>, +) -> bool { + stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { + let here = match (*n.expr_data.clone()).clone() { + ExprData::ExprCall { + call_semantics: cs, .. + } => match (*crate::v1_std_core::call_semantics_target(cs.clone())).clone() { + CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner, + decl_name: decl, + .. + } => match crate::v1_compiler_emit::lookup_item_by_identity( + registry.clone(), + Rc::new(DeclaredCallableIdentity { + owner_module_path: owner.clone(), + decl_name: decl.clone(), + }), + ) { + Some(info) => { + crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()) + } + std::option::Option::None => false, + }, + _ => false, + }, + ExprData::ExprMethodCall { + method_semantics: ms, + .. + } => match ms.clone().as_deref().cloned() { + Some(MethodSemantics::ServiceMethodSemantics { .. }) => { + crate::v1_compiler_infer_service::is_typed_service_call_receiver( + crate::v1_std_core::method_receiver(n.clone()), + source_indices.clone(), + ) + } + _ => false, + }, + _ => false, + }; + (here.clone() || { + let mut __found = false; + for c in n.children.clone().iter().cloned() { + if rust_expr_reaches_awaited_call( + c.clone(), + registry.clone(), + source_indices.clone(), + ) { + __found = true; + break; + } + } + __found + }) + }) +} + pub fn fold_lambda_element_unused( lambda_expr: Rc, source_indices: Rc>>, diff --git a/src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs b/src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs new file mode 100644 index 00000000000..a79b8037a00 --- /dev/null +++ b/src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs @@ -0,0 +1,176 @@ +//! A fold whose step reaches an effectful callee must compile and run at the emitted-Rust +//! boundary. Before the effectful-step loop realization (v1.compiler.emit_rust +//! emit_rust_effectful_fold_loop) the step was handed to `Iterator::fold` as a synchronous +//! closure and the callee's `.await?` landed inside it: rustc E0728. Run with +//! cargo test -p v1-compiler --test effectful_fold_step_emitted_rust. Like its siblings this +//! target is compiled by all-target clippy and not executed by required CI +//! (gunbc.rung_drop rust_unit_tests_off_the_merge_path). + +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::rc::Rc; + +use v1_compiler::v1_compiler_artifact::RenderTarget; +use v1_compiler::v1_compiler_compile::{compile_sources, SourceFile}; +use v1_compiler::v1_std_core::diagnostic_to_message; + +// The step calls `scaled`, which reads its resource and is therefore effectful; the record +// accumulator mirrors gunbc.auth.approval_decision_store pending_escalations. The pure fold is +// the control that the closure realization is kept where the step is pure. +const SOURCE: &str = r#"module effectful_fold_probe + +type FoldNet { base: Int } + +type FoldTally { sum: Int, seen: Int } + +fn scaled(n: Int) -> Int + uses net: FoldNet +{ + net.base * n +} + +fn tally(xs: List) -> FoldTally + uses net: FoldNet +{ + fold(xs, init: FoldTally { sum: 0, seen: 0 }, f: (acc, x) => FoldTally { sum: acc.sum + scaled(n: x), seen: acc.seen + 1 }) +} + +fn pure_total(xs: List) -> Int { + fold(xs, init: 0, f: (acc, x) => acc + x) +} +"#; + +struct Scratch(PathBuf); + +impl Drop for Scratch { + fn drop(&mut self) { + let _ = std::fs::remove_dir_all(&self.0); + } +} + +fn unique_rlib(deps: &Path, name: &str) -> PathBuf { + let prefix = format!("lib{name}-"); + let matches: Vec<_> = std::fs::read_dir(deps) + .expect("read test dependency directory") + .map(|entry| entry.expect("read dependency entry").path()) + .filter(|path| { + let filename = path.file_name().unwrap().to_string_lossy(); + filename.starts_with(&prefix) && filename.ends_with(".rlib") + }) + .collect(); + assert_eq!( + matches.len(), + 1, + "ambiguous or absent {name} artifact: {matches:?}" + ); + matches[0].clone() +} + +#[test] +fn an_effectful_fold_step_emits_buildable_and_correct_rust() { + let result = compile_sources( + Rc::new( + vec![Rc::new(SourceFile { + path: "effectful_fold_probe.dag".into(), + content: SOURCE.into(), + })] + .into(), + ), + RenderTarget::Rust, + ); + let modules: Vec<_> = result + .files + .iter() + .filter(|file| file.path == "src/effectful_fold_probe.rs") + .collect(); + assert_eq!( + modules.len(), + 1, + "emission did not produce the specimen: {:?}", + result + .diagnostics + .iter() + .map(|d| diagnostic_to_message(d.diagnostic.clone())) + .collect::>() + ); + let emitted = modules[0].content.to_string(); + assert!( + emitted.contains("for __fold_elem in"), + "the effectful step was not realized as a loop:\n{emitted}" + ); + assert!( + emitted.contains(".fold("), + "the pure fold lost its closure realization:\n{emitted}" + ); + let root = std::env::temp_dir().join(format!("gunbc-effectful-fold-{}", std::process::id())); + std::fs::create_dir(&root).expect("create isolated specimen directory"); + let scratch = Scratch(root); + std::fs::write( + scratch.0.join("effectful_fold_probe.rs"), + &modules[0].content, + ) + .expect("retain emitted bytes unchanged"); + // The emitted futures never suspend (the only effect is a resource field read), so one + // poll with a no-op waker drives them to completion; a Pending is a harness refusal. + std::fs::write( + scratch.0.join("main.rs"), + r#"pub use v1_compiler::*; +mod effectful_fold_probe; +fn block_on(f: F) -> F::Output { + let mut f = std::pin::pin!(f); + let mut cx = std::task::Context::from_waker(std::task::Waker::noop()); + match f.as_mut().poll(&mut cx) { + std::task::Poll::Ready(v) => v, + std::task::Poll::Pending => panic!("emitted future suspended with no executor"), + } +} +fn main() { + use std::rc::Rc; + use effectful_fold_probe::{FoldNet, pure_total, tally}; + let net = FoldNet { base: 10 }; + let xs = Rc::new(im::vector![1, 2, 3]); + let t = block_on(tally(xs.clone(), &net)).expect("effectful fold refused"); + assert_eq!(t.sum, 60); + assert_eq!(t.seen, 3); + let empty = block_on(tally(Rc::new(im::vector![]), &net)).expect("empty fold refused"); + assert_eq!(empty.sum, 0); + assert_eq!(empty.seen, 0); + assert_eq!(pure_total(xs), 6); +} +"#, + ) + .expect("write harness around emitted module"); + let executable = std::env::current_exe().expect("locate test executable"); + let deps = executable.parent().expect("test dependency directory"); + let output = Command::new("rustc") + .arg("--edition=2021") + .arg(scratch.0.join("main.rs")) + .arg("-L") + .arg(format!("dependency={}", deps.display())) + .arg("--extern") + .arg(format!( + "v1_compiler={}", + unique_rlib(deps, "v1_compiler").display() + )) + .arg("--extern") + .arg(format!("im={}", unique_rlib(deps, "im").display())) + .arg("--extern") + .arg(format!("serde={}", unique_rlib(deps, "serde").display())) + .arg("-o") + .arg(scratch.0.join("specimen")) + .output() + .expect("invoke rustc on emitted specimen"); + assert!( + output.status.success(), + "emitted Rust refused: {}\n--- emitted module ---\n{emitted}", + String::from_utf8_lossy(&output.stderr) + ); + let run = Command::new(scratch.0.join("specimen")) + .output() + .expect("execute compiled specimen"); + assert!( + run.status.success(), + "effectful fold behavior failed: {}", + String::from_utf8_lossy(&run.stderr) + ); +} From 6be3086e4353aa277dad6fce7f0ca9d9a34a8db6 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sat, 3 Oct 2026 21:10:23 +0000 Subject: [PATCH 2/6] stage0 mirror: regenerate v1_compiler_emit_rust.rs over the merged tree (required-regen; second pass is a fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 212 +++++++++++++++++---- 1 file changed, 175 insertions(+), 37 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 4c82c355d4c..a60e8f6b8af 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -27135,6 +27135,17 @@ pub fn emit_typed_collection_lambda( } } +pub fn rust_fold_safe_acc_type(acc_type_str: String) -> String { + if (((acc_type_str.clone() == "Rc>".to_string()) + || (acc_type_str.clone() == "Vec<()>".to_string())) + || (acc_type_str.clone() == "Option<()>".to_string())) + { + "_".to_string() + } else { + acc_type_str.clone() + } +} + pub fn emit_typed_fold_lambda( lambda_expr: Rc, acc_type_str: String, @@ -27162,14 +27173,7 @@ pub fn emit_typed_fold_lambda( .skip(1 as usize) .collect::>(), ); - let safe_acc_type = if (((acc_type_str.clone() == "Rc>".to_string()) - || (acc_type_str.clone() == "Vec<()>".to_string())) - || (acc_type_str.clone() == "Option<()>".to_string())) - { - "_".to_string() - } else { - acc_type_str.clone() - }; + let safe_acc_type = rust_fold_safe_acc_type(acc_type_str.clone()); let fallback_types = Rc::new({ let mut __result = Vec::new(); for pair in Rc::new( @@ -27731,22 +27735,6 @@ pub fn emit_rust_fold_method_call( ), std::option::Option::None => false, }; - let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { - Some(a) => emit_typed_fold_lambda( - crate::v1_std_core::arg_value(a.clone()), - lambda_acc_type_str.clone(), - fold_elem_type_str.clone(), - elem_unused.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - fold_emit_info.clone(), - ), - std::option::Option::None => { - "compile_error!(\"missing fold function argument\")".to_string() - } - }; let iter_template = if elem_unused.clone() { v1_rt::replace( sharing.iter_owned.clone(), @@ -27756,28 +27744,178 @@ pub fn emit_rust_fold_method_call( } else { sharing.iter_owned.clone() }; - v1_rt::concat( - v1_rt::concat( + let iter_str = crate::v1_compiler_emit_core_support::apply_type_template1( + iter_template.clone(), + recv_str.clone(), + ); + let step_awaits = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => rust_expr_reaches_awaited_call( + crate::v1_std_core::arg_value(a.clone()), + registry.clone(), + scope.type_env.clone().source_indices.clone(), + ), + std::option::Option::None => false, + }; + if step_awaits.clone() { + emit_rust_effectful_fold_loop( + fold_lambda_node.clone(), + iter_str.clone(), + init_str.clone(), + lambda_acc_type_str.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ) + } else { + { + let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => emit_typed_fold_lambda( + crate::v1_std_core::arg_value(a.clone()), + lambda_acc_type_str.clone(), + fold_elem_type_str.clone(), + elem_unused.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ), + std::option::Option::None => { + "compile_error!(\"missing fold function argument\")".to_string() + } + }; v1_rt::concat( v1_rt::concat( v1_rt::concat( - crate::v1_compiler_emit_core_support::apply_type_template1( - iter_template.clone(), - recv_str.clone(), + v1_rt::concat( + v1_rt::concat(iter_str.clone(), ".fold(".to_string()), + init_str.clone(), ), - ".fold(".to_string(), + ", ".to_string(), ), - init_str.clone(), + fold_fn.clone(), ), - ", ".to_string(), - ), - fold_fn.clone(), - ), - ")".to_string(), - ) + ")".to_string(), + ) + } + } } } +pub fn emit_rust_effectful_fold_loop( + lambda_expr: Rc, + iter_str: String, + init_str: String, + acc_type_str: String, + registry: Rc>>, + scope: Rc, + depth: i64, + shared_types: Rc>, + emit_info: Rc, +) -> String { + match (*lambda_expr.expr_data.clone()).clone() { + ExprData::ExprLambda => { + let si = scope.type_env.clone().source_indices.clone(); +let ps = crate::v1_std_core::lambda_param_names_at(lambda_expr.clone(), si.clone()); +let pn = Rc::new(lambda_expr.children.clone().iter().cloned().skip(1 as usize).collect::>()); +let acc_param_type = rust_fold_safe_acc_type(acc_type_str.clone()); +let acc_name = match ps.clone().first().cloned() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let elem_name = match ps.clone().iter().cloned().skip(1 as usize).next() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let lambda_scope = lambda_scope_from_children(scope.clone(), ps.clone(), pn.clone()); +let body_str = emit_typed_expr(crate::v1_std_core::lambda_body(lambda_expr.clone()), registry.clone(), lambda_scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone(), 1024); +let acc_ident = if (acc_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(acc_name.clone(), RenderTarget::Rust) + }; +let elem_ident = if (elem_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(elem_name.clone(), RenderTarget::Rust) + }; +let acc_decl = if ((acc_param_type.clone() == "_".to_string()) || (acc_param_type.clone() == "".to_string())) { + "".to_string() + } else { + v1_rt::concat(": ".to_string(), acc_param_type.clone()) + }; +let acc_unwrap = if ((acc_name.clone() != "_".to_string()) && v1_rt::set_contains(&emit_info.owned_bindings.clone(), acc_name.clone())) { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("let ".to_string(), acc_ident.clone()), " = v1_rt::take_owned(".to_string()), acc_ident.clone()), "); ".to_string()) + } else { + "".to_string() + }; +v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("{ let mut __fold_acc".to_string(), acc_decl.clone()), " = ".to_string()), init_str.clone()), "; ".to_string()), "for __fold_elem in ".to_string()), iter_str.clone()), " { ".to_string()), "let ".to_string()), acc_ident.clone()), " = __fold_acc; ".to_string()), acc_unwrap.clone()), "let ".to_string()), elem_ident.clone()), " = __fold_elem; ".to_string()), "__fold_acc = { ".to_string()), body_str.clone()), " }; ".to_string()), "} __fold_acc }".to_string()) +}, + _ => emit_rust_compile_error_expr("effectful fold step is not a lambda: an effectful function value has no synchronous closure realization and no loop realization".to_string()), +} +} + +pub fn rust_expr_reaches_awaited_call( + n: Rc, + registry: Rc>>, + source_indices: Rc>>, +) -> bool { + stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { + let here = match (*n.expr_data.clone()).clone() { + ExprData::ExprCall { + call_semantics: cs, .. + } => match (*crate::v1_std_core::call_semantics_target(cs.clone())).clone() { + CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner, + decl_name: decl, + .. + } => match crate::v1_compiler_emit::lookup_item_by_identity( + registry.clone(), + Rc::new(DeclaredCallableIdentity { + owner_module_path: owner.clone(), + decl_name: decl.clone(), + }), + ) { + Some(info) => { + crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()) + } + std::option::Option::None => false, + }, + _ => false, + }, + ExprData::ExprMethodCall { + method_semantics: ms, + .. + } => match ms.clone().as_deref().cloned() { + Some(MethodSemantics::ServiceMethodSemantics { .. }) => { + crate::v1_compiler_infer_service::is_typed_service_call_receiver( + crate::v1_std_core::method_receiver(n.clone()), + source_indices.clone(), + ) + } + _ => false, + }, + _ => false, + }; + (here.clone() || { + let mut __found = false; + for c in n.children.clone().iter().cloned() { + if rust_expr_reaches_awaited_call( + c.clone(), + registry.clone(), + source_indices.clone(), + ) { + __found = true; + break; + } + } + __found + }) + }) +} + pub fn fold_lambda_element_unused( lambda_expr: Rc, source_indices: Rc>>, From 09f864545a2bc1e1ea43611be2b7563b5d194c3e Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 4 Oct 2026 00:10:19 +0000 Subject: [PATCH 3/6] NativeClaimDriver: a declared resource set {Filesystem}; the main binds the filesystem_io handler when the report demands it Co-Authored-By: Claude Opus 5.5 (1M context) --- .../instruments/native_emission_controls.dag | 27 +++- dag/std/compiler_entry.dag | 10 +- src/v1/05_emit_rust.dag | 100 +++++++++++--- src/v1/stage0/src/v1_compiler_emit_rust.rs | 124 +++++++++++++++++- 4 files changed, 238 insertions(+), 23 deletions(-) diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index 66231d1d616..5a2d990f6ed 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -2,6 +2,7 @@ module gunbc.instruments.native_emission_controls import std.types { Bool, List, Set, String } import v2.std.algebra { filter } +import extdeps.filesystem.filesystem_io { Filesystem } import std.compiler_entry { CompilerEntryDriver, NativeClaimDriver, NativeClaimReport, NativeClaimTerminal, NativeClaimHeld, NativeClaimNotHeld } // THE NATIVE EMISSION CONTROLS: one small carrier per Rust-emitter rule, EMITTED, BUILT AND RUN as a @@ -46,6 +47,18 @@ type ControlDisclosure { context: C } +// RULE: the NativeClaimDriver binds its declared Filesystem resource (std.compiler_entry +// NativeClaimDriver; v1.compiler.emit_rust native_claim_report_effect_demand). Reaching Filesystem +// makes native_claim_report effectful, so this whole program runs only if the rendered main binds +// the filesystem_io handler and awaits the report: remove the binding and the main calls an async, +// handler-taking report with neither, which rustc refuses -- the red is the label's, not a row's. +// The path sits under a root no host provisions, so +// the case decides the same way everywhere. +fn control_absent_path_read_is_refused() -> Bool { + let read = Filesystem.Read(path: "/gunbc-native-emission-controls-absent/none") + !read.success && read.error != "" +} + type NativeEmissionCase { identity: String held: Bool @@ -92,17 +105,27 @@ fn header_bound_cases() -> List { ] } +fn claim_driver_filesystem_cases() -> List { + [ + NativeEmissionCase { + identity: "claim_driver_filesystem_absent_path_read_is_refused", + held: control_absent_path_read_is_refused() + } + ] +} + data native_emission_expected_identities: List = [ "set_struct_eq_same_members_in_another_order", "set_struct_eq_red_bare_field_differs", "set_struct_eq_red_set_member_differs", "set_struct_eq_red_everyone_is_not_a_listing", "set_and_list_struct_eq_same_fields", - "set_and_list_struct_eq_red_list_order_differs" + "set_and_list_struct_eq_red_list_order_differs", + "claim_driver_filesystem_absent_path_read_is_refused" ] fn native_emission_cases() -> List { - header_bound_cases() + concat(header_bound_cases(), claim_driver_filesystem_cases()) } fn case_row(c: NativeEmissionCase) -> String { diff --git a/dag/std/compiler_entry.dag b/dag/std/compiler_entry.dag index 5dbd2e2d71b..e15f9d97dd2 100644 --- a/dag/std/compiler_entry.dag +++ b/dag/std/compiler_entry.dag @@ -90,8 +90,14 @@ import std.measure { // this partition admits. Its `.dag` entry declares one fold, `native_claim_report() -> // NativeClaimReport`, which computes every case, renders one row per case identity and decides the // terminal; -// the rendered main performs only the two operations no fold can -- writing stdout and setting the -// status -- and reads no argv and no file. It exists because a claim that must EXECUTE natively has +// the rendered main performs only the operations no fold can -- writing stdout and setting the +// status -- and reads no argv. Its DECLARED RESOURCE SET is {Filesystem}: a report that reaches no +// effect gets a synchronous main that binds nothing, and a report whose only demand is the +// Filesystem service gets that service bound to the existing extdeps.filesystem.filesystem_io +// handler, the binding NativeCliDriver's main already performs, with a transport error reported as +// no observation. Any other demand is refused at emission in place of a main +// (v1.compiler.emit_rust native_claim_report_effect_demand), so a claim cannot reach an effect this +// driver has not declared. It exists because a claim that must EXECUTE natively has // no other door: the required-v2-native lane runs v2.test.* claims inside the emitted compiler's own // evaluator, which interprets the claim's closure rather than emitting it, and NativeCliDriver's main // is the compile CLI's (source-root walk and plan folds), so reusing it would give one arm two diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 77499d4dfb9..157b35488a8 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -3589,7 +3589,7 @@ fn emit_rust_selected(typed: ResolvedGraph, selection: RustModuleRenderSelection renders_clap_cli: has_pipeline, renders_async_services: has_services }) - let main_file = emit_main_rs(modules: typed.modules, has_services: has_services, crate_name: crate_name) + let main_file = emit_main_rs(modules: typed.modules, has_services: has_services, crate_name: crate_name, registry: ctx.registry) let cli_dispatch_file = if has_pipeline { [emit_gunbc_cli_dispatch_generated(crate_name: crate_name)] } else { [] } let rt_file = emit_v2_rt_module() let compiler_tests_file = if has_pipeline { [emit_compiler_tests_module()] } else { [] } @@ -17521,7 +17521,7 @@ fn emit_gunbc_cli_dispatch_generated(crate_name: String) -> TextFile { // a library: its main is the typed entry-point-absent refusal. The derived "workflow" CLI that used // to answer below the pipeline arms -- one clap subcommand per function carrying `uses` or reaching // a service -- is deleted: it renamed the effect axis an entry role, and no built closure reached it. -fn emit_main_rs(modules: List, has_services: Bool, crate_name: String) -> TextFile { +fn emit_main_rs(modules: List, has_services: Bool, crate_name: String, registry: Map) -> TextFile { let retained_host_pipeline = compiler_pipeline_entry_is_retained_host(modules: modules) let pipeline_module = compiler_pipeline_entry_module_name(modules: modules) if compiler_pipeline_entry_is_ambiguous(modules: modules) { @@ -17543,7 +17543,11 @@ fn emit_main_rs(modules: List, has_services: Bool, crate_name: Stri return emit_native_cli_driver_main_rs(crate_name: crate_name, pipeline_module: pipeline_module) } if compiler_pipeline_entry_is_native_claim(modules: modules) { - return emit_native_claim_driver_main_rs(crate_name: crate_name, pipeline_module: pipeline_module) + return emit_native_claim_driver_main_rs( + crate_name: crate_name, + pipeline_module: pipeline_module, + demand: native_claim_report_effect_demand(registry: registry, pipeline_module: pipeline_module) + ) } if compiler_pipeline_entry_is_direct_ingest(modules: modules) { return emit_direct_ingest_driver_main_rs(crate_name: crate_name, pipeline_module: pipeline_module) @@ -17688,8 +17692,83 @@ fn emit_host_source_root_read_rs(crate_name: String) -> String { // gunbc test reads (0 held, 1 not held, 2 no observation). No code is taken from the program, so no // program can reach a fourth status or a failure spelled as 0. The reason goes to stderr so the case // rows on stdout stay the whole observation a reader joins by identity. -fn emit_native_claim_driver_main_rs(crate_name: String, pipeline_module: String) -> TextFile { +// WHAT THE REPORT DEMANDS OF ITS HOST, read from the one effect authority (item_is_effectful_callee +// over the registry row the report's declaration produces), never from the entry module's imports. +// The declared resource set of a NativeClaimDriver is {Filesystem}: a pure report gets the sync main +// below unchanged, a report whose only demand is the Filesystem service gets that service bound to +// the existing filesystem_io handler -- the binding NativeCliDriver's main already performs -- and +// anything else is a typed refusal in place of a main, because binding an effect this driver does +// not declare would be a transport no row admitted. +type NativeClaimEffectDemand + = NativeClaimPure + | NativeClaimFilesystem + | NativeClaimUndeclaredEffect { detail: String } + +fn native_claim_report_effect_demand(registry: Map, pipeline_module: String) -> NativeClaimEffectDemand { + match lookup_item_by_identity(registry: registry, id: DeclaredCallableIdentity { owner_module_path: pipeline_module, decl_name: "native_claim_report" }) { + Present { value: info } => + if !item_is_effectful_callee(info: info) { NativeClaimPure } + else if (item_resource_names(info: info) |> count) == 0 && (info.service_names |> count) == 1 && (info.service_names |> all(sn => service_var_name(service_name: sn) == "filesystem")) { NativeClaimFilesystem } + else { NativeClaimUndeclaredEffect { detail: concat("services [", concat(info.service_names |> join(separator: ", "), concat("] resources [", concat(item_resource_names(info: info) |> join(separator: ", "), "]")))) } } + Absent => NativeClaimUndeclaredEffect { detail: "native_claim_report has no registry row" } + } +} + +fn emit_native_claim_driver_main_rs(crate_name: String, pipeline_module: String, demand: NativeClaimEffectDemand) -> TextFile { let pipeline_mod = module_to_filename(name: pipeline_module) + match demand { + NativeClaimPure => emit_native_claim_driver_pure_main_rs(crate_name: crate_name, pipeline_mod: pipeline_mod) + NativeClaimFilesystem => emit_native_claim_driver_filesystem_main_rs(crate_name: crate_name, pipeline_mod: pipeline_mod) + NativeClaimUndeclaredEffect { detail } => TextFile { + path: concat(rust_source_root(), "main", rust_source_ext()), + content: concat("// Generated by v1 compiler -- do not edit.\n\ncompile_error!(\"REFUSED: a NativeClaimDriver report may demand only the Filesystem service; ", concat(escape_string_literal_body(s: detail), "\");\n")) + } + } +} + +// The report's terminal mapping is shared by both mains: held 0, not held 1, no observation 2. +fn native_claim_terminal_exit_lines() -> String { + concat( + " print!(\"\{\}\", report.stdout);", "\n", + " match &*report.terminal \{", "\n", + " NativeClaimTerminal::NativeClaimHeld => std::process::exit(0),", "\n", + " NativeClaimTerminal::NativeClaimNotHeld \{ reason \} => \{", "\n", + " eprintln!(\"NOT HELD: \{reason\}\");", "\n", + " std::process::exit(1);", "\n", + " \}", "\n", + " NativeClaimTerminal::NativeClaimNoObservation \{ reason \} => \{", "\n", + " eprintln!(\"NO OBSERVATION: \{reason\}\");", "\n", + " std::process::exit(2);", "\n", + " \}", "\n", + " \}", "\n") +} + +// A transport error out of the bound handler is no observation (2), never a held or not-held case: +// the report did not finish deciding. +fn emit_native_claim_driver_filesystem_main_rs(crate_name: String, pipeline_mod: String) -> TextFile { + TextFile { + path: concat(rust_source_root(), "main", rust_source_ext()), + content: concat( + "// Generated by v1 compiler -- do not edit.", "\n", + "\n", + "#![allow(unused_parens, clippy::all, clippy::disallowed_macros)]", "\n", + "\n", + "use ", crate_name, "::std_compiler_entry::NativeClaimTerminal;", "\n", + "use ", crate_name, "::", pipeline_mod, "::native_claim_report;", "\n", + "\n", + "#[tokio::main(flavor = \"current_thread\")]", "\n", + "async fn main() \{", "\n", + " let filesystem = ", crate_name, "::extdeps_filesystem_filesystem_io::Filesystem::new(Default::default());", "\n", + " let report = match native_claim_report(&filesystem).await \{", "\n", + " Ok(report) => report,", "\n", + " Err(cause) => \{ eprintln!(\"NO OBSERVATION: native filesystem transport: \{\}\", cause); std::process::exit(2); \}", "\n", + " \};", "\n", + native_claim_terminal_exit_lines(), + "\}", "\n") + } +} + +fn emit_native_claim_driver_pure_main_rs(crate_name: String, pipeline_mod: String) -> TextFile { TextFile { path: concat(rust_source_root(), "main", rust_source_ext()), content: concat( @@ -17702,18 +17781,7 @@ fn emit_native_claim_driver_main_rs(crate_name: String, pipeline_module: String) "\n", "fn main() \{", "\n", " let report = native_claim_report();", "\n", - " print!(\"\{\}\", report.stdout);", "\n", - " match &*report.terminal \{", "\n", - " NativeClaimTerminal::NativeClaimHeld => std::process::exit(0),", "\n", - " NativeClaimTerminal::NativeClaimNotHeld \{ reason \} => \{", "\n", - " eprintln!(\"NOT HELD: \{reason\}\");", "\n", - " std::process::exit(1);", "\n", - " \}", "\n", - " NativeClaimTerminal::NativeClaimNoObservation \{ reason \} => \{", "\n", - " eprintln!(\"NO OBSERVATION: \{reason\}\");", "\n", - " std::process::exit(2);", "\n", - " \}", "\n", - " \}", "\n", + native_claim_terminal_exit_lines(), "\}", "\n") } } diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 8edc0f33d10..22e643e05d0 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -6,6 +6,7 @@ use self::ClosedAliasPeelVerdict::*; use self::FmArmAnalysis::*; use self::FmLoweringRefusal::*; use self::IterOwnedReceiverCloneDisposition::*; +use self::NativeClaimEffectDemand::*; use self::WitnessCtorPathVerdict::*; pub use crate::extdeps_cargo::CargoFeature; pub use crate::extdeps_cargo_version::render_cargo_package_header_prefix; @@ -7064,6 +7065,7 @@ pub fn emit_rust_selected( typed.modules.clone(), has_services.clone(), crate_name.clone(), + ctx.registry.clone(), ); let cli_dispatch_file = if has_pipeline.clone() { Rc::new(vec![emit_gunbc_cli_dispatch_generated(crate_name.clone())]) @@ -40269,6 +40271,7 @@ pub fn emit_main_rs( modules: Rc>>, has_services: bool, crate_name: String, + registry: Rc>>, ) -> Rc { { let retained_host_pipeline = compiler_pipeline_entry_is_retained_host(modules.clone()); @@ -40304,6 +40307,10 @@ pub fn emit_main_rs( return emit_native_claim_driver_main_rs( crate_name.clone(), pipeline_module.clone(), + native_claim_report_effect_demand( + registry.clone(), + pipeline_module.clone(), + ), ); } if compiler_pipeline_entry_is_direct_ingest(modules.clone()) { @@ -40384,20 +40391,131 @@ pub fn emit_host_source_root_read_rs(crate_name: String) -> String { v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("fn read_ingest(source_roots: &[String]) -> Vec> {\n".to_string(), " let filesystem = ".to_string()), crate_name.clone()), "::extdeps_filesystem_filesystem_io::Filesystem::new(Default::default());\n".to_string()), " let runtime = match tokio::runtime::Builder::new_current_thread().build() { Ok(runtime) => runtime, Err(cause) => { eprintln!(\"REFUSED: native filesystem executor: {}\", cause); std::process::exit(2); } };\n".to_string()), " let observed = runtime.block_on(".to_string()), crate_name.clone()), "::gunbc_source_root_read::source_root_read(Rc::new(source_roots.iter().cloned().collect()), &filesystem));\n".to_string()), " match observed {\n".to_string()), " Ok(files) => match &*files {\n".to_string()), " ".to_string()), crate_name.clone()), "::gunbc_source_root_read::SourceRootFiles::SourceRootFilesRead { files } =>\n".to_string()), " ".to_string()), crate_name.clone()), "::v2_compiler_source_authority::source_root_ingest_from_files(files.clone()).iter().cloned().collect(),\n".to_string()), " ".to_string()), crate_name.clone()), "::gunbc_source_root_read::SourceRootFiles::SourceRootFilesRefused { path, kind, cause } => {\n".to_string()), " eprintln!(\"REFUSED: could not read source root at {} [{}]: {}\", path, kind, cause); std::process::exit(2);\n".to_string()), " }\n".to_string()), " },\n".to_string()), " Err(cause) => { eprintln!(\"REFUSED: native filesystem transport: {}\", cause); std::process::exit(2); }\n".to_string()), " }\n".to_string()), "}\n".to_string()) } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum NativeClaimEffectDemand { + NativeClaimPure, + NativeClaimFilesystem, + NativeClaimUndeclaredEffect { detail: String }, +} +impl NativeClaimEffectDemand { + pub fn detail(&self) -> String { + match self { + NativeClaimEffectDemand::NativeClaimPure => panic!("no detail on unit variant"), + NativeClaimEffectDemand::NativeClaimFilesystem => panic!("no detail on unit variant"), + NativeClaimEffectDemand::NativeClaimUndeclaredEffect { detail: __val, .. } => { + __val.clone() + } + } + } +} + +pub fn native_claim_report_effect_demand( + registry: Rc>>, + pipeline_module: String, +) -> Rc { + match crate::v1_compiler_emit::lookup_item_by_identity( + registry.clone(), + Rc::new(DeclaredCallableIdentity { + owner_module_path: pipeline_module.clone(), + decl_name: "native_claim_report".to_string(), + }), + ) { + Some(info) => { + if !crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()) { + Rc::new(NativeClaimEffectDemand::NativeClaimPure) + } else { + if ((((crate::v1_compiler_infer_items::item_resource_names(info.clone()).len() + as i64) + == 0) + && ((info.service_names.clone().len() as i64) == 1)) + && { + let mut __all = true; + for sn in info.service_names.clone().iter().cloned() { + if !(crate::v1_compiler_emit_core_support::service_var_name(sn.clone()) + == "filesystem".to_string()) + { + __all = false; + break; + } + } + __all + }) + { + Rc::new(NativeClaimEffectDemand::NativeClaimFilesystem) + } else { + Rc::new(NativeClaimEffectDemand::NativeClaimUndeclaredEffect { + detail: v1_rt::concat( + "services [".to_string(), + v1_rt::concat( + info.service_names.clone().join(&", ".to_string()), + v1_rt::concat( + "] resources [".to_string(), + v1_rt::concat( + crate::v1_compiler_infer_items::item_resource_names( + info.clone(), + ) + .join(&", ".to_string()), + "]".to_string(), + ), + ), + ), + ), + }) + } + } + } + std::option::Option::None => { + Rc::new(NativeClaimEffectDemand::NativeClaimUndeclaredEffect { + detail: "native_claim_report has no registry row".to_string(), + }) + } + } +} + pub fn emit_native_claim_driver_main_rs( crate_name: String, pipeline_module: String, + demand: Rc, ) -> Rc { { let pipeline_mod = crate::gunbc_rust_emitted_edge::module_to_filename(pipeline_module.clone()); - Rc::new(TextFile { + match (*demand.clone()).clone() { + NativeClaimEffectDemand::NativeClaimPure => emit_native_claim_driver_pure_main_rs(crate_name.clone(), pipeline_mod.clone()), + NativeClaimEffectDemand::NativeClaimFilesystem => emit_native_claim_driver_filesystem_main_rs(crate_name.clone(), pipeline_mod.clone()), + NativeClaimEffectDemand::NativeClaimUndeclaredEffect { detail: detail, .. } => Rc::new(TextFile { path: v1_rt::concat(v1_rt::concat(rust_source_root(), "main".to_string()), rust_source_ext()), - content: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("// Generated by v1 compiler -- do not edit.".to_string(), "\n".to_string()), "\n".to_string()), "#![allow(unused_parens, clippy::all, clippy::disallowed_macros)]".to_string()), "\n".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::std_compiler_entry::NativeClaimTerminal;".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::".to_string()), pipeline_mod.clone()), "::native_claim_report;".to_string()), "\n".to_string()), "\n".to_string()), "fn main() {".to_string()), "\n".to_string()), " let report = native_claim_report();".to_string()), "\n".to_string()), " print!(\"{}\", report.stdout);".to_string()), "\n".to_string()), " match &*report.terminal {".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimHeld => std::process::exit(0),".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNotHeld { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NOT HELD: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(1);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNoObservation { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NO OBSERVATION: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(2);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), "}".to_string()), "\n".to_string()), -}) + content: v1_rt::concat("// Generated by v1 compiler -- do not edit.\n\ncompile_error!(\"REFUSED: a NativeClaimDriver report may demand only the Filesystem service; ".to_string(), v1_rt::concat(crate::v1_compiler_emit_core_support::escape_string_literal_body(detail.clone()), "\");\n".to_string())), +}), +} } } +pub fn native_claim_terminal_exit_lines() -> String { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" print!(\"{}\", report.stdout);".to_string(), "\n".to_string()), " match &*report.terminal {".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimHeld => std::process::exit(0),".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNotHeld { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NOT HELD: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(1);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNoObservation { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NO OBSERVATION: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(2);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()) +} + +pub fn emit_native_claim_driver_filesystem_main_rs( + crate_name: String, + pipeline_mod: String, +) -> Rc { + Rc::new(TextFile { + path: v1_rt::concat(v1_rt::concat(rust_source_root(), "main".to_string()), rust_source_ext()), + content: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("// Generated by v1 compiler -- do not edit.".to_string(), "\n".to_string()), "\n".to_string()), "#![allow(unused_parens, clippy::all, clippy::disallowed_macros)]".to_string()), "\n".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::std_compiler_entry::NativeClaimTerminal;".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::".to_string()), pipeline_mod.clone()), "::native_claim_report;".to_string()), "\n".to_string()), "\n".to_string()), "#[tokio::main(flavor = \"current_thread\")]".to_string()), "\n".to_string()), "async fn main() {".to_string()), "\n".to_string()), " let filesystem = ".to_string()), crate_name.clone()), "::extdeps_filesystem_filesystem_io::Filesystem::new(Default::default());".to_string()), "\n".to_string()), " let report = match native_claim_report(&filesystem).await {".to_string()), "\n".to_string()), " Ok(report) => report,".to_string()), "\n".to_string()), " Err(cause) => { eprintln!(\"NO OBSERVATION: native filesystem transport: {}\", cause); std::process::exit(2); }".to_string()), "\n".to_string()), " };".to_string()), "\n".to_string()), native_claim_terminal_exit_lines()), "}".to_string()), "\n".to_string()), +}) +} + +pub fn emit_native_claim_driver_pure_main_rs( + crate_name: String, + pipeline_mod: String, +) -> Rc { + Rc::new(TextFile { + path: v1_rt::concat(v1_rt::concat(rust_source_root(), "main".to_string()), rust_source_ext()), + content: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("// Generated by v1 compiler -- do not edit.".to_string(), "\n".to_string()), "\n".to_string()), "#![allow(unused_parens, clippy::all, clippy::disallowed_macros)]".to_string()), "\n".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::std_compiler_entry::NativeClaimTerminal;".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::".to_string()), pipeline_mod.clone()), "::native_claim_report;".to_string()), "\n".to_string()), "\n".to_string()), "fn main() {".to_string()), "\n".to_string()), " let report = native_claim_report();".to_string()), "\n".to_string()), native_claim_terminal_exit_lines()), "}".to_string()), "\n".to_string()), +}) +} + pub fn emit_native_cli_driver_main_rs(crate_name: String, pipeline_module: String) -> Rc { { let pipeline_mod = From d896e4f02c612f005416e1ee2e057f7a78dc6222 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 4 Oct 2026 00:32:01 +0000 Subject: [PATCH 4/6] stage0 mirror: regenerate v1_compiler_emit_rust.rs over the merged tree Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 124 ++++++++++++++++++++- 1 file changed, 121 insertions(+), 3 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 8c556a25a7c..e72968972c6 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -6,6 +6,7 @@ use self::ClosedAliasPeelVerdict::*; use self::FmArmAnalysis::*; use self::FmLoweringRefusal::*; use self::IterOwnedReceiverCloneDisposition::*; +use self::NativeClaimEffectDemand::*; use self::WitnessCtorPathVerdict::*; pub use crate::extdeps_cargo::CargoFeature; pub use crate::extdeps_cargo_version::render_cargo_package_header_prefix; @@ -7063,6 +7064,7 @@ pub fn emit_rust_selected( typed.modules.clone(), has_services.clone(), crate_name.clone(), + ctx.registry.clone(), ); let cli_dispatch_file = if has_pipeline.clone() { Rc::new(vec![emit_gunbc_cli_dispatch_generated(crate_name.clone())]) @@ -40117,6 +40119,7 @@ pub fn emit_main_rs( modules: Rc>>, has_services: bool, crate_name: String, + registry: Rc>>, ) -> Rc { { let retained_host_pipeline = compiler_pipeline_entry_is_retained_host(modules.clone()); @@ -40152,6 +40155,10 @@ pub fn emit_main_rs( return emit_native_claim_driver_main_rs( crate_name.clone(), pipeline_module.clone(), + native_claim_report_effect_demand( + registry.clone(), + pipeline_module.clone(), + ), ); } if compiler_pipeline_entry_is_direct_ingest(modules.clone()) { @@ -40232,20 +40239,131 @@ pub fn emit_host_source_root_read_rs(crate_name: String) -> String { v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("fn read_ingest(source_roots: &[String]) -> Vec> {\n".to_string(), " let filesystem = ".to_string()), crate_name.clone()), "::extdeps_filesystem_filesystem_io::Filesystem::new(Default::default());\n".to_string()), " let runtime = match tokio::runtime::Builder::new_current_thread().build() { Ok(runtime) => runtime, Err(cause) => { eprintln!(\"REFUSED: native filesystem executor: {}\", cause); std::process::exit(2); } };\n".to_string()), " let observed = runtime.block_on(".to_string()), crate_name.clone()), "::gunbc_source_root_read::source_root_read(Rc::new(source_roots.iter().cloned().collect()), &filesystem));\n".to_string()), " match observed {\n".to_string()), " Ok(files) => match &*files {\n".to_string()), " ".to_string()), crate_name.clone()), "::gunbc_source_root_read::SourceRootFiles::SourceRootFilesRead { files } =>\n".to_string()), " ".to_string()), crate_name.clone()), "::v2_compiler_source_authority::source_root_ingest_from_files(files.clone()).iter().cloned().collect(),\n".to_string()), " ".to_string()), crate_name.clone()), "::gunbc_source_root_read::SourceRootFiles::SourceRootFilesRefused { path, kind, cause } => {\n".to_string()), " eprintln!(\"REFUSED: could not read source root at {} [{}]: {}\", path, kind, cause); std::process::exit(2);\n".to_string()), " }\n".to_string()), " },\n".to_string()), " Err(cause) => { eprintln!(\"REFUSED: native filesystem transport: {}\", cause); std::process::exit(2); }\n".to_string()), " }\n".to_string()), "}\n".to_string()) } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[serde(tag = "_variant")] +pub enum NativeClaimEffectDemand { + NativeClaimPure, + NativeClaimFilesystem, + NativeClaimUndeclaredEffect { detail: String }, +} +impl NativeClaimEffectDemand { + pub fn detail(&self) -> String { + match self { + NativeClaimEffectDemand::NativeClaimPure => panic!("no detail on unit variant"), + NativeClaimEffectDemand::NativeClaimFilesystem => panic!("no detail on unit variant"), + NativeClaimEffectDemand::NativeClaimUndeclaredEffect { detail: __val, .. } => { + __val.clone() + } + } + } +} + +pub fn native_claim_report_effect_demand( + registry: Rc>>, + pipeline_module: String, +) -> Rc { + match crate::v1_compiler_emit::lookup_item_by_identity( + registry.clone(), + Rc::new(DeclaredCallableIdentity { + owner_module_path: pipeline_module.clone(), + decl_name: "native_claim_report".to_string(), + }), + ) { + Some(info) => { + if !crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()) { + Rc::new(NativeClaimEffectDemand::NativeClaimPure) + } else { + if ((((crate::v1_compiler_infer_items::item_resource_names(info.clone()).len() + as i64) + == 0) + && ((info.service_names.clone().len() as i64) == 1)) + && { + let mut __all = true; + for sn in info.service_names.clone().iter().cloned() { + if !(crate::v1_compiler_emit_core_support::service_var_name(sn.clone()) + == "filesystem".to_string()) + { + __all = false; + break; + } + } + __all + }) + { + Rc::new(NativeClaimEffectDemand::NativeClaimFilesystem) + } else { + Rc::new(NativeClaimEffectDemand::NativeClaimUndeclaredEffect { + detail: v1_rt::concat( + "services [".to_string(), + v1_rt::concat( + info.service_names.clone().join(&", ".to_string()), + v1_rt::concat( + "] resources [".to_string(), + v1_rt::concat( + crate::v1_compiler_infer_items::item_resource_names( + info.clone(), + ) + .join(&", ".to_string()), + "]".to_string(), + ), + ), + ), + ), + }) + } + } + } + std::option::Option::None => { + Rc::new(NativeClaimEffectDemand::NativeClaimUndeclaredEffect { + detail: "native_claim_report has no registry row".to_string(), + }) + } + } +} + pub fn emit_native_claim_driver_main_rs( crate_name: String, pipeline_module: String, + demand: Rc, ) -> Rc { { let pipeline_mod = crate::gunbc_rust_emitted_edge::module_to_filename(pipeline_module.clone()); - Rc::new(TextFile { + match (*demand.clone()).clone() { + NativeClaimEffectDemand::NativeClaimPure => emit_native_claim_driver_pure_main_rs(crate_name.clone(), pipeline_mod.clone()), + NativeClaimEffectDemand::NativeClaimFilesystem => emit_native_claim_driver_filesystem_main_rs(crate_name.clone(), pipeline_mod.clone()), + NativeClaimEffectDemand::NativeClaimUndeclaredEffect { detail: detail, .. } => Rc::new(TextFile { path: v1_rt::concat(v1_rt::concat(rust_source_root(), "main".to_string()), rust_source_ext()), - content: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("// Generated by v1 compiler -- do not edit.".to_string(), "\n".to_string()), "\n".to_string()), "#![allow(unused_parens, clippy::all, clippy::disallowed_macros)]".to_string()), "\n".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::std_compiler_entry::NativeClaimTerminal;".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::".to_string()), pipeline_mod.clone()), "::native_claim_report;".to_string()), "\n".to_string()), "\n".to_string()), "fn main() {".to_string()), "\n".to_string()), " let report = native_claim_report();".to_string()), "\n".to_string()), " print!(\"{}\", report.stdout);".to_string()), "\n".to_string()), " match &*report.terminal {".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimHeld => std::process::exit(0),".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNotHeld { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NOT HELD: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(1);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNoObservation { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NO OBSERVATION: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(2);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), "}".to_string()), "\n".to_string()), -}) + content: v1_rt::concat("// Generated by v1 compiler -- do not edit.\n\ncompile_error!(\"REFUSED: a NativeClaimDriver report may demand only the Filesystem service; ".to_string(), v1_rt::concat(crate::v1_compiler_emit_core_support::escape_string_literal_body(detail.clone()), "\");\n".to_string())), +}), +} } } +pub fn native_claim_terminal_exit_lines() -> String { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(" print!(\"{}\", report.stdout);".to_string(), "\n".to_string()), " match &*report.terminal {".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimHeld => std::process::exit(0),".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNotHeld { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NOT HELD: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(1);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " NativeClaimTerminal::NativeClaimNoObservation { reason } => {".to_string()), "\n".to_string()), " eprintln!(\"NO OBSERVATION: {reason}\");".to_string()), "\n".to_string()), " std::process::exit(2);".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()), " }".to_string()), "\n".to_string()) +} + +pub fn emit_native_claim_driver_filesystem_main_rs( + crate_name: String, + pipeline_mod: String, +) -> Rc { + Rc::new(TextFile { + path: v1_rt::concat(v1_rt::concat(rust_source_root(), "main".to_string()), rust_source_ext()), + content: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("// Generated by v1 compiler -- do not edit.".to_string(), "\n".to_string()), "\n".to_string()), "#![allow(unused_parens, clippy::all, clippy::disallowed_macros)]".to_string()), "\n".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::std_compiler_entry::NativeClaimTerminal;".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::".to_string()), pipeline_mod.clone()), "::native_claim_report;".to_string()), "\n".to_string()), "\n".to_string()), "#[tokio::main(flavor = \"current_thread\")]".to_string()), "\n".to_string()), "async fn main() {".to_string()), "\n".to_string()), " let filesystem = ".to_string()), crate_name.clone()), "::extdeps_filesystem_filesystem_io::Filesystem::new(Default::default());".to_string()), "\n".to_string()), " let report = match native_claim_report(&filesystem).await {".to_string()), "\n".to_string()), " Ok(report) => report,".to_string()), "\n".to_string()), " Err(cause) => { eprintln!(\"NO OBSERVATION: native filesystem transport: {}\", cause); std::process::exit(2); }".to_string()), "\n".to_string()), " };".to_string()), "\n".to_string()), native_claim_terminal_exit_lines()), "}".to_string()), "\n".to_string()), +}) +} + +pub fn emit_native_claim_driver_pure_main_rs( + crate_name: String, + pipeline_mod: String, +) -> Rc { + Rc::new(TextFile { + path: v1_rt::concat(v1_rt::concat(rust_source_root(), "main".to_string()), rust_source_ext()), + content: v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("// Generated by v1 compiler -- do not edit.".to_string(), "\n".to_string()), "\n".to_string()), "#![allow(unused_parens, clippy::all, clippy::disallowed_macros)]".to_string()), "\n".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::std_compiler_entry::NativeClaimTerminal;".to_string()), "\n".to_string()), "use ".to_string()), crate_name.clone()), "::".to_string()), pipeline_mod.clone()), "::native_claim_report;".to_string()), "\n".to_string()), "\n".to_string()), "fn main() {".to_string()), "\n".to_string()), " let report = native_claim_report();".to_string()), "\n".to_string()), native_claim_terminal_exit_lines()), "}".to_string()), "\n".to_string()), +}) +} + pub fn emit_native_cli_driver_main_rs(crate_name: String, pipeline_module: String) -> Rc { { let pipeline_mod = From 308bb2953589c60dad07b9125323fc9a2e396f59 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 4 Oct 2026 00:54:02 +0000 Subject: [PATCH 5/6] native-emission-controls: effectful fold step cases (replaces the hand-written test); stage0 mirror regenerated Co-Authored-By: Claude Opus 5.5 (1M context) --- .../instruments/native_emission_controls.dag | 38 +++- src/v1/stage0/src/v1_compiler_emit_rust.rs | 212 +++++++++++++++--- 2 files changed, 211 insertions(+), 39 deletions(-) diff --git a/dag/gunbc/instruments/native_emission_controls.dag b/dag/gunbc/instruments/native_emission_controls.dag index dc95e36f008..7f9b7e1ae33 100644 --- a/dag/gunbc/instruments/native_emission_controls.dag +++ b/dag/gunbc/instruments/native_emission_controls.dag @@ -147,6 +147,37 @@ fn claim_driver_filesystem_cases() -> List { ] } +// RULE: an effectful fold step is realized as a loop in the enclosing async frame +// (v1.compiler.emit_rust emit_rust_effectful_fold_loop). Iterator::fold takes its step as a +// synchronous closure, so a step that reaches an effectful callee put that callee's `.await?` inside +// it: E0728, the shape of gunbc.auth.approval_decision_store pending_escalations. The step here +// reads Filesystem for every element and accumulates a record, as that fold does. Every path sits +// under a root no host provisions, so each read is a typed refusal and the counts are decided +// everywhere; the red rows are the record's two fields and the empty list. +type ControlReadTally { + refused: Int + seen: Int +} + +fn control_tally_absent_reads(paths: List) -> ControlReadTally { + fold(paths, init: ControlReadTally { refused: 0, seen: 0 }, f: (acc, p) => + let read = Filesystem.Read(path: p) + ControlReadTally { refused: if read.success { acc.refused } else { acc.refused + 1 }, seen: acc.seen + 1 } + ) +} + +fn control_absent_paths() -> List { + ["/gunbc-native-emission-controls-absent/a", "/gunbc-native-emission-controls-absent/b", "/gunbc-native-emission-controls-absent/c"] +} + +fn effectful_fold_step_cases() -> List { + [ + NativeEmissionCase { identity: "effectful_fold_step_counts_every_refused_read", held: control_tally_absent_reads(paths: control_absent_paths()).refused == 3 }, + NativeEmissionCase { identity: "effectful_fold_step_red_seen_counts_elements", held: control_tally_absent_reads(paths: control_absent_paths()).seen == 3 }, + NativeEmissionCase { identity: "effectful_fold_step_red_empty_keeps_init", held: control_tally_absent_reads(paths: []).seen == 0 } + ] +} + data native_emission_expected_identities: List = [ "set_struct_eq_same_members_in_another_order", "set_struct_eq_red_bare_field_differs", @@ -163,11 +194,14 @@ data native_emission_expected_identities: List = [ "filter_guard_receipt_blank_tail_accepts", "filter_guard_receipt_red_nonblank_tail_refuses", "filter_guard_receipt_red_empty_tag_short_circuits", - "claim_driver_filesystem_absent_path_read_is_refused" + "claim_driver_filesystem_absent_path_read_is_refused", + "effectful_fold_step_counts_every_refused_read", + "effectful_fold_step_red_seen_counts_elements", + "effectful_fold_step_red_empty_keeps_init" ] fn native_emission_cases() -> List { - concat(concat(header_bound_cases(), filter_in_branch_condition_cases()), claim_driver_filesystem_cases()) + concat(concat(header_bound_cases(), filter_in_branch_condition_cases()), concat(claim_driver_filesystem_cases(), effectful_fold_step_cases())) } fn case_row(c: NativeEmissionCase) -> String { diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index e72968972c6..e80cdc6bcfb 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -26914,6 +26914,17 @@ pub fn emit_typed_collection_lambda( } } +pub fn rust_fold_safe_acc_type(acc_type_str: String) -> String { + if (((acc_type_str.clone() == "Rc>".to_string()) + || (acc_type_str.clone() == "Vec<()>".to_string())) + || (acc_type_str.clone() == "Option<()>".to_string())) + { + "_".to_string() + } else { + acc_type_str.clone() + } +} + pub fn emit_typed_fold_lambda( lambda_expr: Rc, acc_type_str: String, @@ -26941,14 +26952,7 @@ pub fn emit_typed_fold_lambda( .skip(1 as usize) .collect::>(), ); - let safe_acc_type = if (((acc_type_str.clone() == "Rc>".to_string()) - || (acc_type_str.clone() == "Vec<()>".to_string())) - || (acc_type_str.clone() == "Option<()>".to_string())) - { - "_".to_string() - } else { - acc_type_str.clone() - }; + let safe_acc_type = rust_fold_safe_acc_type(acc_type_str.clone()); let fallback_types = Rc::new({ let mut __result = Vec::new(); for pair in Rc::new( @@ -27510,22 +27514,6 @@ pub fn emit_rust_fold_method_call( ), std::option::Option::None => false, }; - let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { - Some(a) => emit_typed_fold_lambda( - crate::v1_std_core::arg_value(a.clone()), - lambda_acc_type_str.clone(), - fold_elem_type_str.clone(), - elem_unused.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - fold_emit_info.clone(), - ), - std::option::Option::None => { - "compile_error!(\"missing fold function argument\")".to_string() - } - }; let iter_template = if elem_unused.clone() { v1_rt::replace( sharing.iter_owned.clone(), @@ -27535,28 +27523,178 @@ pub fn emit_rust_fold_method_call( } else { sharing.iter_owned.clone() }; - v1_rt::concat( - v1_rt::concat( + let iter_str = crate::v1_compiler_emit_core_support::apply_type_template1( + iter_template.clone(), + recv_str.clone(), + ); + let step_awaits = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => rust_expr_reaches_awaited_call( + crate::v1_std_core::arg_value(a.clone()), + registry.clone(), + scope.type_env.clone().source_indices.clone(), + ), + std::option::Option::None => false, + }; + if step_awaits.clone() { + emit_rust_effectful_fold_loop( + fold_lambda_node.clone(), + iter_str.clone(), + init_str.clone(), + lambda_acc_type_str.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ) + } else { + { + let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => emit_typed_fold_lambda( + crate::v1_std_core::arg_value(a.clone()), + lambda_acc_type_str.clone(), + fold_elem_type_str.clone(), + elem_unused.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ), + std::option::Option::None => { + "compile_error!(\"missing fold function argument\")".to_string() + } + }; v1_rt::concat( v1_rt::concat( v1_rt::concat( - crate::v1_compiler_emit_core_support::apply_type_template1( - iter_template.clone(), - recv_str.clone(), + v1_rt::concat( + v1_rt::concat(iter_str.clone(), ".fold(".to_string()), + init_str.clone(), ), - ".fold(".to_string(), + ", ".to_string(), ), - init_str.clone(), + fold_fn.clone(), ), - ", ".to_string(), - ), - fold_fn.clone(), - ), - ")".to_string(), - ) + ")".to_string(), + ) + } + } } } +pub fn emit_rust_effectful_fold_loop( + lambda_expr: Rc, + iter_str: String, + init_str: String, + acc_type_str: String, + registry: Rc>>, + scope: Rc, + depth: i64, + shared_types: Rc>, + emit_info: Rc, +) -> String { + match (*lambda_expr.expr_data.clone()).clone() { + ExprData::ExprLambda => { + let si = scope.type_env.clone().source_indices.clone(); +let ps = crate::v1_std_core::lambda_param_names_at(lambda_expr.clone(), si.clone()); +let pn = Rc::new(lambda_expr.children.clone().iter().cloned().skip(1 as usize).collect::>()); +let acc_param_type = rust_fold_safe_acc_type(acc_type_str.clone()); +let acc_name = match ps.clone().first().cloned() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let elem_name = match ps.clone().iter().cloned().skip(1 as usize).next() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let lambda_scope = lambda_scope_from_children(scope.clone(), ps.clone(), pn.clone()); +let body_str = emit_typed_expr(crate::v1_std_core::lambda_body(lambda_expr.clone()), registry.clone(), lambda_scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone(), 1024); +let acc_ident = if (acc_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(acc_name.clone(), RenderTarget::Rust) + }; +let elem_ident = if (elem_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(elem_name.clone(), RenderTarget::Rust) + }; +let acc_decl = if ((acc_param_type.clone() == "_".to_string()) || (acc_param_type.clone() == "".to_string())) { + "".to_string() + } else { + v1_rt::concat(": ".to_string(), acc_param_type.clone()) + }; +let acc_unwrap = if ((acc_name.clone() != "_".to_string()) && v1_rt::set_contains(&emit_info.owned_bindings.clone(), acc_name.clone())) { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("let ".to_string(), acc_ident.clone()), " = v1_rt::take_owned(".to_string()), acc_ident.clone()), "); ".to_string()) + } else { + "".to_string() + }; +v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("{ let mut __fold_acc".to_string(), acc_decl.clone()), " = ".to_string()), init_str.clone()), "; ".to_string()), "for __fold_elem in ".to_string()), iter_str.clone()), " { ".to_string()), "let ".to_string()), acc_ident.clone()), " = __fold_acc; ".to_string()), acc_unwrap.clone()), "let ".to_string()), elem_ident.clone()), " = __fold_elem; ".to_string()), "__fold_acc = { ".to_string()), body_str.clone()), " }; ".to_string()), "} __fold_acc }".to_string()) +}, + _ => emit_rust_compile_error_expr("effectful fold step is not a lambda: an effectful function value has no synchronous closure realization and no loop realization".to_string()), +} +} + +pub fn rust_expr_reaches_awaited_call( + n: Rc, + registry: Rc>>, + source_indices: Rc>>, +) -> bool { + stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { + let here = match (*n.expr_data.clone()).clone() { + ExprData::ExprCall { + call_semantics: cs, .. + } => match (*crate::v1_std_core::call_semantics_target(cs.clone())).clone() { + CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner, + decl_name: decl, + .. + } => match crate::v1_compiler_emit::lookup_item_by_identity( + registry.clone(), + Rc::new(DeclaredCallableIdentity { + owner_module_path: owner.clone(), + decl_name: decl.clone(), + }), + ) { + Some(info) => { + crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()) + } + std::option::Option::None => false, + }, + _ => false, + }, + ExprData::ExprMethodCall { + method_semantics: ms, + .. + } => match ms.clone().as_deref().cloned() { + Some(MethodSemantics::ServiceMethodSemantics { .. }) => { + crate::v1_compiler_infer_service::is_typed_service_call_receiver( + crate::v1_std_core::method_receiver(n.clone()), + source_indices.clone(), + ) + } + _ => false, + }, + _ => false, + }; + (here.clone() || { + let mut __found = false; + for c in n.children.clone().iter().cloned() { + if rust_expr_reaches_awaited_call( + c.clone(), + registry.clone(), + source_indices.clone(), + ) { + __found = true; + break; + } + } + __found + }) + }) +} + pub fn fold_lambda_element_unused( lambda_expr: Rc, source_indices: Rc>>, From 25d98b725efcace74e069667e9524a43a82b05be Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 4 Oct 2026 06:12:40 +0000 Subject: [PATCH 6/6] stage0 mirror: regenerate v1_compiler_emit_rust.rs over the merged tree Co-Authored-By: Claude Opus 5.5 (1M context) --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 212 +++++++++++++++++---- 1 file changed, 175 insertions(+), 37 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 0994f20b173..b60b777f449 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -27018,6 +27018,17 @@ pub fn emit_typed_collection_lambda( } } +pub fn rust_fold_safe_acc_type(acc_type_str: String) -> String { + if (((acc_type_str.clone() == "Rc>".to_string()) + || (acc_type_str.clone() == "Vec<()>".to_string())) + || (acc_type_str.clone() == "Option<()>".to_string())) + { + "_".to_string() + } else { + acc_type_str.clone() + } +} + pub fn emit_typed_fold_lambda( lambda_expr: Rc, acc_type_str: String, @@ -27045,14 +27056,7 @@ pub fn emit_typed_fold_lambda( .skip(1 as usize) .collect::>(), ); - let safe_acc_type = if (((acc_type_str.clone() == "Rc>".to_string()) - || (acc_type_str.clone() == "Vec<()>".to_string())) - || (acc_type_str.clone() == "Option<()>".to_string())) - { - "_".to_string() - } else { - acc_type_str.clone() - }; + let safe_acc_type = rust_fold_safe_acc_type(acc_type_str.clone()); let fallback_types = Rc::new({ let mut __result = Vec::new(); for pair in Rc::new( @@ -27614,22 +27618,6 @@ pub fn emit_rust_fold_method_call( ), std::option::Option::None => false, }; - let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { - Some(a) => emit_typed_fold_lambda( - crate::v1_std_core::arg_value(a.clone()), - lambda_acc_type_str.clone(), - fold_elem_type_str.clone(), - elem_unused.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - fold_emit_info.clone(), - ), - std::option::Option::None => { - "compile_error!(\"missing fold function argument\")".to_string() - } - }; let iter_template = if elem_unused.clone() { v1_rt::replace( sharing.iter_owned.clone(), @@ -27639,28 +27627,178 @@ pub fn emit_rust_fold_method_call( } else { sharing.iter_owned.clone() }; - v1_rt::concat( - v1_rt::concat( + let iter_str = crate::v1_compiler_emit_core_support::apply_type_template1( + iter_template.clone(), + recv_str.clone(), + ); + let step_awaits = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => rust_expr_reaches_awaited_call( + crate::v1_std_core::arg_value(a.clone()), + registry.clone(), + scope.type_env.clone().source_indices.clone(), + ), + std::option::Option::None => false, + }; + if step_awaits.clone() { + emit_rust_effectful_fold_loop( + fold_lambda_node.clone(), + iter_str.clone(), + init_str.clone(), + lambda_acc_type_str.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ) + } else { + { + let fold_fn = match args.clone().iter().cloned().skip(1 as usize).next() { + Some(a) => emit_typed_fold_lambda( + crate::v1_std_core::arg_value(a.clone()), + lambda_acc_type_str.clone(), + fold_elem_type_str.clone(), + elem_unused.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + fold_emit_info.clone(), + ), + std::option::Option::None => { + "compile_error!(\"missing fold function argument\")".to_string() + } + }; v1_rt::concat( v1_rt::concat( v1_rt::concat( - crate::v1_compiler_emit_core_support::apply_type_template1( - iter_template.clone(), - recv_str.clone(), + v1_rt::concat( + v1_rt::concat(iter_str.clone(), ".fold(".to_string()), + init_str.clone(), ), - ".fold(".to_string(), + ", ".to_string(), ), - init_str.clone(), + fold_fn.clone(), ), - ", ".to_string(), - ), - fold_fn.clone(), - ), - ")".to_string(), - ) + ")".to_string(), + ) + } + } } } +pub fn emit_rust_effectful_fold_loop( + lambda_expr: Rc, + iter_str: String, + init_str: String, + acc_type_str: String, + registry: Rc>>, + scope: Rc, + depth: i64, + shared_types: Rc>, + emit_info: Rc, +) -> String { + match (*lambda_expr.expr_data.clone()).clone() { + ExprData::ExprLambda => { + let si = scope.type_env.clone().source_indices.clone(); +let ps = crate::v1_std_core::lambda_param_names_at(lambda_expr.clone(), si.clone()); +let pn = Rc::new(lambda_expr.children.clone().iter().cloned().skip(1 as usize).collect::>()); +let acc_param_type = rust_fold_safe_acc_type(acc_type_str.clone()); +let acc_name = match ps.clone().first().cloned() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let elem_name = match ps.clone().iter().cloned().skip(1 as usize).next() { + Some(n) => n.clone(), + std::option::Option::None => "_".to_string(), +}; +let lambda_scope = lambda_scope_from_children(scope.clone(), ps.clone(), pn.clone()); +let body_str = emit_typed_expr(crate::v1_std_core::lambda_body(lambda_expr.clone()), registry.clone(), lambda_scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone(), 1024); +let acc_ident = if (acc_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(acc_name.clone(), RenderTarget::Rust) + }; +let elem_ident = if (elem_name.clone() == "_".to_string()) { + "_".to_string() + } else { + crate::v1_compiler_emit::emit_ident(elem_name.clone(), RenderTarget::Rust) + }; +let acc_decl = if ((acc_param_type.clone() == "_".to_string()) || (acc_param_type.clone() == "".to_string())) { + "".to_string() + } else { + v1_rt::concat(": ".to_string(), acc_param_type.clone()) + }; +let acc_unwrap = if ((acc_name.clone() != "_".to_string()) && v1_rt::set_contains(&emit_info.owned_bindings.clone(), acc_name.clone())) { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("let ".to_string(), acc_ident.clone()), " = v1_rt::take_owned(".to_string()), acc_ident.clone()), "); ".to_string()) + } else { + "".to_string() + }; +v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("{ let mut __fold_acc".to_string(), acc_decl.clone()), " = ".to_string()), init_str.clone()), "; ".to_string()), "for __fold_elem in ".to_string()), iter_str.clone()), " { ".to_string()), "let ".to_string()), acc_ident.clone()), " = __fold_acc; ".to_string()), acc_unwrap.clone()), "let ".to_string()), elem_ident.clone()), " = __fold_elem; ".to_string()), "__fold_acc = { ".to_string()), body_str.clone()), " }; ".to_string()), "} __fold_acc }".to_string()) +}, + _ => emit_rust_compile_error_expr("effectful fold step is not a lambda: an effectful function value has no synchronous closure realization and no loop realization".to_string()), +} +} + +pub fn rust_expr_reaches_awaited_call( + n: Rc, + registry: Rc>>, + source_indices: Rc>>, +) -> bool { + stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { + let here = match (*n.expr_data.clone()).clone() { + ExprData::ExprCall { + call_semantics: cs, .. + } => match (*crate::v1_std_core::call_semantics_target(cs.clone())).clone() { + CallTargetIdentity::SourceDeclarationCall { + owner_module_path: owner, + decl_name: decl, + .. + } => match crate::v1_compiler_emit::lookup_item_by_identity( + registry.clone(), + Rc::new(DeclaredCallableIdentity { + owner_module_path: owner.clone(), + decl_name: decl.clone(), + }), + ) { + Some(info) => { + crate::v1_compiler_infer_items::item_is_effectful_callee(info.clone()) + } + std::option::Option::None => false, + }, + _ => false, + }, + ExprData::ExprMethodCall { + method_semantics: ms, + .. + } => match ms.clone().as_deref().cloned() { + Some(MethodSemantics::ServiceMethodSemantics { .. }) => { + crate::v1_compiler_infer_service::is_typed_service_call_receiver( + crate::v1_std_core::method_receiver(n.clone()), + source_indices.clone(), + ) + } + _ => false, + }, + _ => false, + }; + (here.clone() || { + let mut __found = false; + for c in n.children.clone().iter().cloned() { + if rust_expr_reaches_awaited_call( + c.clone(), + registry.clone(), + source_indices.clone(), + ) { + __found = true; + break; + } + } + __found + }) + }) +} + pub fn fold_lambda_element_unused( lambda_expr: Rc, source_indices: Rc>>,