From 5f12d042309fffa112fa7b97e35f1637a7b3f2d3 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 04:36:39 +0000 Subject: [PATCH 01/30] Emitted v2 compiler crate: a declaration's identity is its last segment, and a primitive with no realization refuses instead of inventing one Two roots behind 175 of the 260 rustc errors on the emitted v2 compiler closure (issue #9664, milestones 1 and 2): - 102 x E0425: the four DeclaredCallableIdentity constructions in v1.compiler.infer_lookup took decl_name from the AUTHORED spelling, so a qualified call carried the whole dotted path as the declaration name and emission rendered crate::v2_std_grammar::v2.std.grammar.f(..). - 73 x E0425: v2.std.algebra length is a ModeledProjection of the `length` primitive and rt_function_registry has no `length` row, so emission took rust_runtime_bridge_name's identity arm and wrote v1_rt::length -- a symbol the seed does not define. A primitive's identity and its per-target realization are two facts; CallTargetIdentity carried only the first, so every emitter had to ASSUME a bridge exists. RuntimePrimitiveCall now carries projected_from, the declaration the roster projected it from, and emit_rust routes to the bridge only when its own registry holds the primitive, falls back to the declaration otherwise, and refuses when neither exists. DeclaredCallableIdentity moves to v1.std.core so the target type can carry it without forking the pair. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- src/v1/00_core.dag | 40 +++++++++++++++++++++++++++++- src/v1/04_infer.dag | 12 ++++----- src/v1/04_lookup.dag | 30 +++++++++++++++++------ src/v1/04_sigs.dag | 18 ++++---------- src/v1/05_emit_rust.dag | 54 +++++++++++++++++++++++++++++++++++------ src/v1/compile.dag | 2 +- 6 files changed, 119 insertions(+), 37 deletions(-) diff --git a/src/v1/00_core.dag b/src/v1/00_core.dag index 2c3ba31126e..9aaa6dfe0d7 100644 --- a/src/v1/00_core.dag +++ b/src/v1/00_core.dag @@ -107,8 +107,46 @@ type VarBindingKind // where the declaration and the primitive genuinely disagree and the declaration is what was // called. CallableTargetUndetermined is a refusal-bearing residue -- it is not permission for // emission to fall back to a name lookup, and emission refuses on it. +// THE DECLARED HALF OF AN IDENTITY, HOISTED SO THE RESOLVED ARM CAN CARRY IT WITHOUT +// CARRYING THE BUILTIN ARM. +// +// `decide_callable_candidates` proves a builtin never answers -- it can make a population +// ambiguous and on its own hands the call back to the known-builtin bridge -- so the owner a +// resolution binds is ALWAYS a declared one. Spelling FuncSigResolved's owner as +// CallableIdentity would therefore admit a state the decision already ruled out, and spelling +// it as a loose owner/decl String pair beside DeclaredCallable would be a second representation +// of the pair v1.compiler.sigs already owns (DESIGN section 3). One record, two consumers. +// +// It is declared HERE rather than in v1.compiler.sigs, its former home, because +// CallTargetIdentity below carries one and this module sits under that one. Re-spelling the pair +// in either direction to avoid the import would fork it. +type DeclaredCallableIdentity { + owner_module_path: String + decl_name: String +} + +// A PRIMITIVE'S IDENTITY AND ITS PER-TARGET REALIZATION ARE TWO FACTS, AND `projected_from` +// IS WHAT KEEPS THEM APART. +// +// The resolver knows both halves at once: that this call resolved to declaration D, and that +// std.primitive_projection says D projects primitive P. It used to record only P, and every +// emitter then had to assume P has a bridge in ITS runtime. That assumption is false and was +// fabricating: v2.std.algebra length is a ModeledProjection of the `length` primitive, the Rust +// registry has no `length` row (its list realization is `count`, its string realization is +// `string_length`), and 05_emit_rust rendered `v1_rt::length` -- a symbol that does not exist in +// the seed -- at 73 sites. That is DESIGN section 5 fabricated-plausible-output: the emitter +// produced a well-formed call to nothing and only rustc refused, downstream of every gate we own. +// +// Which realization a target has is a REALIZATION fact and belongs peripheral to the target +// (DESIGN section 3: the dispatch that selects a realization is itself realization), so the +// resolver states only what it knows and carries the declaration alongside. An emitter routes to +// the bridge when its own registry has the primitive, falls back to the declaration when one was +// projected, and REFUSES otherwise -- it never invents a runtime symbol from a name. +// +// `projected_from` is Absent exactly when the target came from builtin resolution, where no +// declaration answered and there is nothing to fall back to. type CallTargetIdentity - = RuntimePrimitiveCall { primitive_name: String } + = RuntimePrimitiveCall { primitive_name: String, projected_from: DeclaredCallableIdentity? } | SourceDeclarationCall { owner_module_path: String, decl_name: String } | CallableTargetUndetermined diff --git a/src/v1/04_infer.dag b/src/v1/04_infer.dag index f12ac6130be..823902c9938 100644 --- a/src/v1/04_infer.dag +++ b/src/v1/04_infer.dag @@ -5119,7 +5119,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu if node_is_keyed_collection(n: exp, source_indices: scope.type_env.source_indices) { InferResult { typed: make_named_expr_node(occurrence_identity: texpr.occurrence_identity, - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map" } } }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map", projected_from: none } } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: exp } }, span: span, @@ -5133,7 +5133,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Present { value: map_t } => InferResult { typed: make_named_expr_node(occurrence_identity: texpr.occurrence_identity, - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map" } } }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map", projected_from: none } } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: map_t } }, span: span, @@ -5144,7 +5144,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Absent => InferResult { typed: make_named_expr_node(occurrence_identity: texpr.occurrence_identity, - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map" } } }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map", projected_from: none } } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: CompilerError { message: "empty_map(): Map kernel container profile missing (compiler misconfigured)", span: span } }, span: span, @@ -5159,7 +5159,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Present { value: map_t } => InferResult { typed: make_named_expr_node(occurrence_identity: texpr.occurrence_identity, - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map" } } }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map", projected_from: none } } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: Resolved { node: map_t } }, span: span, @@ -5170,7 +5170,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu Absent => InferResult { typed: make_named_expr_node(occurrence_identity: texpr.occurrence_identity, - name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map" } } }, descent_evidence: none }, + name: func_name, expr_data: ExprCall { call_semantics: Present { value: PlainCallSemantics { target: RuntimePrimitiveCall { primitive_name: "empty_map", projected_from: none } } }, descent_evidence: none }, children: typed_arg_nodes, inferred: Present { value: CompilerError { message: "empty_map(): Map kernel container profile missing (compiler misconfigured)", span: span } }, span: span, @@ -5252,7 +5252,7 @@ fn infer_expr_body(texpr: Node, scope: InferScope, expected: Node?) -> InferResu let tier2b = infer_tier2b_builtin_with_kernel_diags(func_name: func_name, typed_args: typed_args, scope: scope, span: span) let bt = tier2b.bt let call_semantics = if func_name == "lookup" { - Present { value: LookupCallSemantics { target: RuntimePrimitiveCall { primitive_name: func_name } } } + Present { value: LookupCallSemantics { target: RuntimePrimitiveCall { primitive_name: func_name, projected_from: none } } } } else { Present { value: PlainCallSemantics { target: resolved_plain_call_target(func_name: func_name, sig_lookup: call_sig_lookup) } } } diff --git a/src/v1/04_lookup.dag b/src/v1/04_lookup.dag index 84f8406d71a..643e5b59421 100644 --- a/src/v1/04_lookup.dag +++ b/src/v1/04_lookup.dag @@ -9,6 +9,7 @@ import std.primitive_projection { } import v1.std.core { + DeclaredCallableIdentity, Node, param_node_type_expr, authored_name_at, NewlineIndex, find_child_named, has_child_named, qualified_last_segment, @@ -58,7 +59,7 @@ import v1.compiler.infer_emit_info { import v1.compiler.infer_sigs { ResolvedFuncSig, ResolvedFuncEnv, lookup_resolved_sig, FuncSigLookup, FuncSigResolved, FuncSigUnresolved, FuncSigAmbiguous, - CallableCandidate, CallableIdentity, DeclaredCallableIdentity, DeclaredCallable, BuiltinCallable, + CallableCandidate, CallableIdentity, DeclaredCallable, BuiltinCallable, parent_closure_callable_candidates, decide_callable_candidates } @@ -231,6 +232,19 @@ fn builtin_is_a_rival_authority(declared: List) -> Bool { declared |> any(c => declared_candidate_rivals_the_builtin(candidate: c)) } +// A DECLARATION'S IDENTITY IS ITS LAST SEGMENT, NEVER THE SPELLING THE CALLER USED. +// +// The four DeclaredCallableIdentity constructions in this module took `decl_name` from the +// authored name. For a qualified call that name is the whole dotted path, so `v2.std.grammar.f(..)` +// resolved with owner `v2.std.grammar` AND decl_name `v2.std.grammar.f`, and 05_emit_rust rendered +// `crate::v2_std_grammar::v2.std.grammar.f(..)` -- 102 E0425s in the v2 compiler closure. The same +// pair also keys `lookup_item` for default-argument filling and `decl_ref` for the primitive +// projection roster, so both silently missed on every qualified call. +// +// `qualified_last_segment` is the idiom `constructor_declaration_for_admission` already uses for +// exactly this, and it is the identity on a bare name -- so it is applied at all four sites rather +// than at the one that was measured failing, which removes the class instead of an instance. +// // TARGET SELECTION, DECIDED HERE AND CONSUMED VERBATIM BY EMISSION. // // A call's target is chosen once, from the declaration resolution actually bound, and 05_emit @@ -249,8 +263,8 @@ fn resolved_declaration_call_target(declared: DeclaredCallableIdentity) -> CallT ) { Present { value: row } => match row.fidelity { - HostRealizedSeam => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive) } - ModeledProjection => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive) } + HostRealizedSeam => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive), projected_from: Present { value: declared } } + ModeledProjection => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive), projected_from: Present { value: declared } } DivergentProjection { divergence: _ } => SourceDeclarationCall { owner_module_path: declared.owner_module_path, decl_name: declared.decl_name } } @@ -274,7 +288,7 @@ fn resolved_plain_call_target(func_name: String, sig_lookup: FuncSigLookup) -> C fn builtin_call_target_or_undetermined(func_name: String) -> CallTargetIdentity { match infer_builtin_call_type(name: func_name) { - Present { value: _ } => RuntimePrimitiveCall { primitive_name: func_name } + Present { value: _ } => RuntimePrimitiveCall { primitive_name: func_name, projected_from: none } Absent => CallableTargetUndetermined } } @@ -347,7 +361,7 @@ fn callable_lookup_over_candidates( ) -> FuncSigLookup { match map_get(func_env.local, name) { Present { value: sig } => - FuncSigResolved { sig: sig, declared: DeclaredCallableIdentity { owner_module_path: func_env.name, decl_name: name } } + FuncSigResolved { sig: sig, declared: DeclaredCallableIdentity { owner_module_path: func_env.name, decl_name: qualified_last_segment(name: name) } } Absent => let declared = parent_closure_callable_candidates(env: func_env, name: name) let builtin_admissible = match author_named_visibility(type_env: type_env, name: name) { @@ -561,7 +575,7 @@ fn borrowed_census_callable_candidate(type_env: TypeEnv, name: String, candidate excluded: excluded ) CallableCandidate { - identity: DeclaredCallable { identity: DeclaredCallableIdentity { owner_module_path: candidate.module_path, decl_name: name } }, + identity: DeclaredCallable { identity: DeclaredCallableIdentity { owner_module_path: candidate.module_path, decl_name: qualified_last_segment(name: name) } }, sig: ResolvedFuncSig { name: name, params: node.params, @@ -606,7 +620,7 @@ fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> FuncSigLookup { is_async: false, output_provenance: [], variant_provenance: empty_map() - }, declared: DeclaredCallableIdentity { owner_module_path: bd.owner_module_path, decl_name: name } } + }, declared: DeclaredCallableIdentity { owner_module_path: bd.owner_module_path, decl_name: qualified_last_segment(name: name) } } } else { let qualified_return = qualify_borrowed_type_names(n: raw_return, owner_module_path: bd.owner_module_path, env: type_env, excluded: excluded) FuncSigResolved { sig: ResolvedFuncSig { @@ -616,7 +630,7 @@ fn func_sig_from_global_bare(type_env: TypeEnv, name: String) -> FuncSigLookup { is_async: false, output_provenance: [], variant_provenance: empty_map() - }, declared: DeclaredCallableIdentity { owner_module_path: bd.owner_module_path, decl_name: name } } + }, declared: DeclaredCallableIdentity { owner_module_path: bd.owner_module_path, decl_name: qualified_last_segment(name: name) } } } } BorrowedCensusDeclAmbiguous { candidates: cands } => diff --git a/src/v1/04_sigs.dag b/src/v1/04_sigs.dag index 3199c92bc3e..cfb236e596a 100644 --- a/src/v1/04_sigs.dag +++ b/src/v1/04_sigs.dag @@ -6,6 +6,7 @@ import v1.std.core { ErrorNode, make_error_node, MissingAnnotation, no_span, DeclaredFuncSig, + DeclaredCallableIdentity, NewlineIndex, authored_name_at } @@ -110,19 +111,10 @@ type ParentSigScan { // the collision this vocabulary exists to describe (gap-analysis row 30 -- `map_get` is both // `v2.std.collection.map_get` returning Outcome> and a builtin returning // Optional). So the candidate is the identity, and the label is a projection of it. -// THE DECLARED HALF OF AN IDENTITY, HOISTED SO THE RESOLVED ARM CAN CARRY IT WITHOUT -// CARRYING THE BUILTIN ARM. -// -// `decide_callable_candidates` proves a builtin never answers -- it can make a population -// ambiguous and on its own hands the call back to the known-builtin bridge -- so the owner a -// resolution binds is ALWAYS a declared one. Spelling FuncSigResolved's owner as -// CallableIdentity would therefore admit a state the decision already ruled out, and spelling -// it as a loose owner/decl String pair beside DeclaredCallable would be a second representation -// of the pair this file already owns (DESIGN section 3). One record, two consumers. -type DeclaredCallableIdentity { - owner_module_path: String - decl_name: String -} +// DeclaredCallableIdentity IS NOT DECLARED HERE ANY MORE. It moved to v1.std.core because +// CallTargetIdentity -- which lives there, below this module -- now carries one, and a second +// spelling of the pair in this file to break the import direction would be the nicknaming defect +// DESIGN section 3 names. The reasoning for the record itself travels with the declaration. type CallableIdentity = DeclaredCallable { identity: DeclaredCallableIdentity } diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 0dd7d0534bb..b33836d3df6 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -18,7 +18,7 @@ import v1.std.core { ExprCast, ExprForEach, ExprIndex, ExprSlice, ExprReturn, make_expr_node, FieldSummary, StoredField, EnumAccessor, OptionalUnwrap, TupleFirst, TupleSecond, OptionalValue, VarBindingKind, LocalValueBinding, FunctionValueBinding, VariantValueBinding, - MatchBoundBinding, CallTargetIdentity, RuntimePrimitiveCall, SourceDeclarationCall, CallableTargetUndetermined, + MatchBoundBinding, CallTargetIdentity, DeclaredCallableIdentity, RuntimePrimitiveCall, SourceDeclarationCall, CallableTargetUndetermined, CallSemantics, PlainCallSemantics, LookupCallSemantics, FunctionValueCallSemantics, MethodSemantics, PlainMethodSemantics, AlgebraMethodSemantics, ServiceMethodSemantics, MatchPattern, field_binding_pattern, TextFile, ErrorNode, make_error_node, InternalError, @@ -8769,8 +8769,16 @@ fn rust_runtime_bridge_passes_receiver_by_ref(function_name: String) -> Bool { // rt_bridge_function_names ever becomes hand-authored rather than derived from // rt_function_registry, a miss stops meaning "spelled the same" and this arm // becomes a fabrication, so that change invalidates this argument. -// An unknown name cannot reach either use of the result, which a reader of this -// function alone cannot see. THE MECHANISM CHANGED WITH CallTargetIdentity and +// AN UNKNOWN NAME COULD REACH THIS, AND DID -- the claim that stood here was false and the +// receipt is worth keeping. `length` is a primitive with a projection row and NO row in +// rt_function_registry, so it arrived as a runtime primitive, missed rt_bridge_function_names, +// took the identity arm, and emitted `v1_rt::length` at 73 sites in the v2 compiler closure -- +// a symbol the seed does not define. The Absent arm was never the defect: the derivation +// argument below is sound for every name the registry HOLDS, and the hole was that nothing +// checked membership first. `rust_runtime_primitive_has_bridge` is now that check, asked before +// this function is reached, so the Absent arm's premise -- this primitive is in the registry and +// merely spelled the same -- is established rather than assumed. +// THE MECHANISM CHANGED WITH CallTargetIdentity and // the argument is restated rather than kept, because the old wording named the // two name-matching guards that no longer exist: emit_typed_call consumed // runtime_name only inside `if is_rt`, and is_rt was @@ -8881,8 +8889,11 @@ fn emit_rust_empty_set_expr(set_type: Node, shared_types: Set, source_in // The method roster had no template on that path -- nothing was lowered by it -- so its wrap was // unpaired by construction. The repair is to pair each wrap with the roster that produced the text // beside it, and at the plain-call position to derive the gate from the SAME predicate that chose -// the emission form (rust_plain_call_emits_as_runtime_bridge, read by emit_typed_call for is_rt and -// by emit_typed_call_expr for the wrap), so no second opinion about the form exists to drift. +// the emission form. That fusion is now stated on the PRIMITIVE's identity rather than the leaf +// spelling: emit_typed_call's is_rt and emit_typed_call_expr's wrap both key on the target's +// runtime_primitive_name, and both ask the same registry, so no second opinion about the form +// exists to drift. rust_plain_call_emits_as_runtime_bridge below is the older leaf-spelling +// statement of that predicate and has no caller. // RUNG (DESIGN 4b): this moves the plain-call half of the class from silent wrongness -- emitted, // compiled by us, refused only by rustc downstream -- to STRUCTURALLY IMPOSSIBLE for the // cross-roster direction specifically: after this change no method-roster row can reach a plain @@ -8958,7 +8969,7 @@ fn call_semantics_target(cs: CallSemantics?) -> CallTargetIdentity { fn call_target_runtime_primitive_name(target: CallTargetIdentity) -> String? { match target { - RuntimePrimitiveCall { primitive_name: primitive_name } => Present { value: primitive_name } + RuntimePrimitiveCall { primitive_name: primitive_name, projected_from: _ } => Present { value: primitive_name } SourceDeclarationCall { owner_module_path: _, decl_name: _ } => none CallableTargetUndetermined => none } @@ -8968,6 +8979,26 @@ fn call_target_is_runtime_primitive(target: CallTargetIdentity) -> Bool { call_target_runtime_primitive_name(target: target) != none } +// THE DECLARATION A RUNTIME TARGET WAS PROJECTED FROM, WHICH IS THE ONLY HONEST ROUTE WHEN THIS +// TARGET HAS NO ROW IN THIS TARGET'S RUNTIME REGISTRY. Absent means builtin resolution produced +// the target and no declaration ever answered, so there is nothing to fall back to and the one +// remaining arm is a refusal. +fn call_target_projected_declaration(target: CallTargetIdentity) -> DeclaredCallableIdentity? { + match target { + RuntimePrimitiveCall { primitive_name: _, projected_from: projected_from } => projected_from + SourceDeclarationCall { owner_module_path: _, decl_name: _ } => none + CallableTargetUndetermined => none + } +} + +// THE REALIZATION HALF OF THE DECISION, ASKED OF THE PRIMITIVE'S OWN IDENTITY RATHER THAN THE +// AUTHORED LEAF SPELLING. `rt_functions()` is derived from rt_function_registry, so membership +// here is exactly `this primitive has a v1_rt realization`. A target that is a runtime primitive +// but has no row is NOT a bridge call, and treating it as one is what emitted `v1_rt::length`. +fn rust_runtime_primitive_has_bridge(primitive_name: String) -> Bool { + map_contains_key(rt_functions(), primitive_name) +} + fn emit_rust_expr_call(expr: Node, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { match expr.expr_data { ExprCall { call_semantics: cs, descent_evidence: _ } => @@ -9535,6 +9566,7 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo Absent => "" } let is_rt = callee_is_function_value == false && target_is_runtime + && rust_runtime_primitive_has_bridge(primitive_name: runtime_primitive_name) let is_rt_ref_map = is_rt && map_contains_key(rt_ref_map_functions(), runtime_primitive_name) let arg_strs = filled_args |> enumerate |> map(pair => let idx = pair.first @@ -9574,8 +9606,14 @@ fn emit_typed_call(func: String, args: List, callee_is_function_value: Boo else { concat("crate::", module_to_filename(name: owner), "::", emit_ident(name: decl, target: Rust)) } CallableTargetUndetermined => emit_error_expr(message: "call target identity was not established before Rust emission", target: Rust) - RuntimePrimitiveCall { primitive_name: _ } => - emit_error_expr(message: "runtime call target lost its bridge identity", target: Rust) + RuntimePrimitiveCall { primitive_name: unbridged_primitive, projected_from: projected_from } => + match projected_from { + Present { value: declared } => + if declared.owner_module_path == scope.module_name { emit_ident(name: declared.decl_name, target: Rust) } + else { concat("crate::", module_to_filename(name: declared.owner_module_path), "::", emit_ident(name: declared.decl_name, target: Rust)) } + Absent => + emit_error_expr(message: concat("primitive ", unbridged_primitive, " has no v1_rt realization and no declaration to emit"), target: Rust) + } } } let func_name = if callee_self_capture { concat(func_ident, ".clone()") } else { func_ident } let call_str = if is_rt && func == "concat" && all_args |> count > 2 { diff --git a/src/v1/compile.dag b/src/v1/compile.dag index 44be7cb8620..f1b21bf910a 100644 --- a/src/v1/compile.dag +++ b/src/v1/compile.dag @@ -385,7 +385,7 @@ fn var_binding_kind_name(value: VarBindingKind) -> String { fn serialize_call_target_identity(value: CallTargetIdentity) -> String { match value { - RuntimePrimitiveCall { primitive_name: primitive_name } => + RuntimePrimitiveCall { primitive_name: primitive_name, projected_from: _ } => concat("{\"kind\": \"RuntimePrimitiveCall\", \"primitive_name\": ", json_quote(s: primitive_name), "}") SourceDeclarationCall { owner_module_path: owner, decl_name: decl } => concat("{\"kind\": \"SourceDeclarationCall\", \"owner_module_path\": ", json_quote(s: owner), ", \"decl_name\": ", json_quote(s: decl), "}") From 15c25ad86e8f7269590fccfb020619802fe45ed4 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 04:48:31 +0000 Subject: [PATCH 02/30] Class B: the algebra method fallback asserted a v1_rt bridge it had not checked tier0 method resolution resolves an ordinary fn-typed RECORD FIELD through lookup_field_in_product, so `algebra.step(..)` arrives as AlgebraMethodSemantics carrying the field node as its method_def. The fallback at the end of that arm hardcoded runtime_bridge: true, which emitted `v1_rt::step` -- and made emit_rust_generic_method_call's own callable-field arm, guarded on runtime_bridge == false, unreachable for the exact receiver it was written for. 65 E0425s on the emitted v2 compiler closure (member, apply, is_empty, step, init, allocate_literal, ...) were that one literal. It now passes the realization question keyed on the same registry as the plain-call seam, so a real bridge method still lowers to a bridge, a callable field lowers as a field, and a name that is neither reaches the existing loud refusal rather than a fabricated symbol. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- src/v1/05_emit_rust.dag | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index b33836d3df6..fdcd70afe2d 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -10246,6 +10246,19 @@ fn emit_rust_first_method_call(receiver: Node, registry: Map, // method's NAME appears in `rt_functions()`, which is the same leaf-spelling re-lookup the call // path above removed: a record field holding a callable named `contains` lost to the bridge // roster purely on spelling. +// +// ONE CALLER DID NOT KNOW, AND SAID `true` ANYWAY. The algebra fallback in emit_typed_method_call +// hardcoded runtime_bridge: true, and tier0 method resolution resolves an ordinary fn-typed RECORD +// FIELD through lookup_field_in_product -- so `algebra.step(..)` arrived as AlgebraMethodSemantics +// with the field node as its method_def, took that fallback, and emitted `v1_rt::step`. The +// callable-field arm directly below exists for exactly that receiver and was unreachable, because +// it is guarded on runtime_bridge == false. 65 E0425s in the v2 compiler closure -- `member`, +// `apply`, `is_empty`, `step`, `init`, `allocate_literal` and friends -- were that one `true`. +// +// It now passes the realization question, keyed on the same registry as the plain-call seam +// (rust_runtime_primitive_has_bridge), so a method that IS a bridge still lowers to one, a +// callable field lowers as a field, and a name that is neither reaches the loud refusal below +// instead of a fabricated v1_rt symbol. fn emit_rust_generic_method_call(method_name: String, receiver: Node, args: List, result_type: InferredNode?, runtime_bridge: Bool, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { let function_name = method_name if runtime_bridge == false && rust_receiver_has_callable_method_field(receiver: receiver, method_name: function_name, scope: scope) { @@ -10348,7 +10361,7 @@ fn emit_typed_method_call(method_call_node: Node, receiver: Node, method: String rust_shared_wrap_ctor(inner_expr: raw) } else { raw } Absent => - emit_rust_generic_method_call(method_name: method_name, receiver: receiver, args: args, result_type: result_type, runtime_bridge: true, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) + emit_rust_generic_method_call(method_name: method_name, receiver: receiver, args: args, result_type: result_type, runtime_bridge: rust_runtime_primitive_has_bridge(primitive_name: method_name), registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } } } From 3d41ffb057b4cce43adb2409a51720c151d0dc22 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 04:49:45 +0000 Subject: [PATCH 03/30] Only ModeledProjection carries projected_from: a HostRealizedSeam body is a self-call, so falling back to it would emit a nonterminating function The declaration fallback is sound only where the declaration's body is real code. HostRealizedSeam means the body IS a self-call, so emitting it compiles and then loops forever -- silent wrongness, strictly worse than the unresolved symbol it would have replaced. A seam whose target has no realization has no honest lowering, so it carries nothing and reaches emission's refusal. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- src/v1/04_lookup.dag | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/v1/04_lookup.dag b/src/v1/04_lookup.dag index 643e5b59421..33ec77e2563 100644 --- a/src/v1/04_lookup.dag +++ b/src/v1/04_lookup.dag @@ -257,13 +257,22 @@ fn builtin_is_a_rival_authority(declared: List) -> Bool { // The runtime NAME comes from the roster row's primitive identity, never from the call's leaf // spelling. That is the whole repair: a bare `contains` resolving to a v2 declaration no longer // reaches the bridge merely because `contains` is also a v1_rt name. +// +// ONLY ModeledProjection CARRIES `projected_from`, AND THE FIDELITY DISTINCTION IS WHY. +// `projected_from` is what an emitter falls back to when its own runtime has no realization for +// the primitive, so it is only sound where the declaration's body is real code -- which is +// precisely what ModeledProjection means. A HostRealizedSeam body is a SELF-CALL by construction +// (decl_facts is `decl_facts(pool_roots: pool_roots)`), so emitting it would produce a +// well-formed, compiling, NONTERMINATING function: silent wrongness, strictly worse than the +// unresolved-symbol refusal it would replace. A seam with no realization in the target has no +// honest lowering at all, so it carries nothing and reaches emission's refusal arm. fn resolved_declaration_call_target(declared: DeclaredCallableIdentity) -> CallTargetIdentity { match primitive_projection_row_for_declaration( declaration: decl_ref(module_path: declared.owner_module_path, decl_name: declared.decl_name) ) { Present { value: row } => match row.fidelity { - HostRealizedSeam => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive), projected_from: Present { value: declared } } + HostRealizedSeam => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive), projected_from: none } ModeledProjection => RuntimePrimitiveCall { primitive_name: primitive_identity_runtime_name(identity: row.primitive), projected_from: Present { value: declared } } DivergentProjection { divergence: _ } => SourceDeclarationCall { owner_module_path: declared.owner_module_path, decl_name: declared.decl_name } From a3938354c39893883bdf3810506089a210f9a1d1 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 05:14:55 +0000 Subject: [PATCH 04/30] M1: realize the two symbol bridges, which were host seams nothing declared to be host seams v2.std.compilers.lexing symbol_lexeme and symbol_intern_lexeme have self-call bodies -- the HostRealizedSeam shape exactly -- and the interpreter has carried real arms for both (v4_bridge.symbol_lexeme, v4_bridge.symbol_intern_lexeme). With no projection roster row the resolver saw ordinary declarations, so Rust emission emitted the declaration, and pub fn symbol_lexeme(sym: String) -> String { symbol_lexeme(sym) } COMPILES. The emitted closure carried two functions that type-check, pass every gate we own, and diverge from the interpreter by not terminating. Unlike the sibling seams (decl_facts and friends, which at least refuse loudly as unresolved v1_rt symbols) nothing anywhere reported this one -- it is absent from the E0425 census precisely because it is silent. extdeps.languages.rust.types already declares Symbol's target type as String, so on this target both bridges are the identity. That is a realization of the declared row, not a second opinion about it. Residue named, not closed: a self-call body is a DECIDABLE structural marker of a host seam, so the compiler could refuse an unrealized one rather than emit it. It does not yet; that check is the class's next-rung trigger. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- dag/extdeps/languages/rust/emit.dag | 5 ++++- dag/std/primitive_identity.dag | 2 ++ dag/std/primitive_projection.dag | 10 ++++++++++ src/v1/runtime_rust.dag | 12 ++++++++++++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/dag/extdeps/languages/rust/emit.dag b/dag/extdeps/languages/rust/emit.dag index eb8d97a3668..bc6be0952ec 100644 --- a/dag/extdeps/languages/rust/emit.dag +++ b/dag/extdeps/languages/rust/emit.dag @@ -255,7 +255,10 @@ data rt_function_registry: List = [ { name: "is_xid_start", bridge_name: "is_xid_start", passes_by_ref: false, wraps_result: false }, { name: "is_xid_continue", bridge_name: "is_xid_continue", passes_by_ref: false, wraps_result: false }, - { name: "is_emoji_ident", bridge_name: "is_emoji_ident", passes_by_ref: false, wraps_result: false } + { name: "is_emoji_ident", bridge_name: "is_emoji_ident", passes_by_ref: false, wraps_result: false }, + + { name: "symbol_lexeme", bridge_name: "symbol_lexeme", passes_by_ref: false, wraps_result: false }, + { name: "symbol_intern_lexeme", bridge_name: "symbol_intern_lexeme", passes_by_ref: false, wraps_result: false } ] fn rt_functions() -> Map { diff --git a/dag/std/primitive_identity.dag b/dag/std/primitive_identity.dag index aa7f80f2806..157368375c9 100644 --- a/dag/std/primitive_identity.dag +++ b/dag/std/primitive_identity.dag @@ -1010,6 +1010,8 @@ data primitive_projection_target_canonical_names: List = [ "data_decl_type_facts", "concept_decl_facts", "concept_decl_facts_live", + "symbol_lexeme", + "symbol_intern_lexeme", ] fn primitive_declared_definitions() -> List { diff --git a/dag/std/primitive_projection.dag b/dag/std/primitive_projection.dag index a252f902ce8..47a2caa21b9 100644 --- a/dag/std/primitive_projection.dag +++ b/dag/std/primitive_projection.dag @@ -53,6 +53,14 @@ data primitive_export_signature_facts: PrimitiveIdentity = primitive_identity_sl data primitive_data_decl_type_facts: PrimitiveIdentity = primitive_identity_slug(name: "data_decl_type_facts") data primitive_concept_decl_facts: PrimitiveIdentity = primitive_identity_slug(name: "concept_decl_facts") data primitive_concept_decl_facts_live: PrimitiveIdentity = primitive_identity_slug(name: "concept_decl_facts_live") +data primitive_symbol_lexeme: PrimitiveIdentity = primitive_identity_slug(name: "symbol_lexeme") +data primitive_symbol_intern_lexeme: PrimitiveIdentity = primitive_identity_slug(name: "symbol_intern_lexeme") + +data symbol_lexeme_seam_disposition_note: String = "THE TWO SYMBOL BRIDGES WERE HOST SEAMS THAT NOTHING SAID WERE HOST SEAMS, and the cost of that silence is why they are rostered here rather than left alone. v2.std.compilers.lexing symbol_lexeme and symbol_intern_lexeme have self-call bodies -- the HostRealizedSeam shape exactly, correct by construction because reaching one recurses to the evaluation-budget refusal -- and the interpreter has carried real arms for both since they were written (gunbc.v1_interpreter_primitive_surface v4_bridge.symbol_lexeme, v4_bridge.symbol_intern_lexeme). But with no roster row the RESOLVER saw an ordinary declaration, so Rust emission emitted the declaration, and `pub fn symbol_lexeme(sym: String) -> String { symbol_lexeme(sym) }` COMPILES. The emitted v2 compiler closure therefore carried two functions that type-check, pass every gate we own, and diverge from the interpreter by not terminating -- the DESIGN section 5 fabricated-plausible-output failure in its quietest form, since unlike the sibling seams (decl_facts and friends, which at least refuse loudly as unresolved v1_rt symbols) nothing anywhere reports this one. + +WHAT MAKES THE RUST REALIZATION HONEST RATHER THAN A SHIM: extdeps.languages.rust.types already declares Symbol's target type as String, so on that target the interning table is the identity and both bridges ARE identity functions. That is a realization of the declared row, not a second opinion about it; a target where Symbol is NOT String would need a different realization and the registry is where it would say so. The interpreter's arms and the Rust registry rows now answer for the same two primitives, which is the agreement that was missing. + +THE RESIDUE IS NAMED, NOT CLOSED: a self-call body is a DECIDABLE structural marker of a host seam, so the compiler could refuse an unrealized one instead of emitting it. It does not yet, and until it does this roster is the only thing standing between a new v4_bridge declaration and another silently nonterminating emission. That check is this class's next-rung trigger." data primitive_projection_roster_note: String = "One row per declaration that is the modeled surface of a declared primitive. Every row was established by READING THE DECLARATION, not by matching its name: the HostRealizedSeam rows are declarations whose whole body is a self-call, and the ModeledProjection rows are declarations with a real body that the builtin arm intercepts ahead of. The single DivergentProjection row is v2.std.collection map_get, whose declared return type is Outcome> against the primitive's Optional; it is carried rather than omitted because omission and divergence are different answers -- omission means nobody has looked, divergence means someone looked and found two authorities. A consumer collecting call candidates must suppress the builtin co-candidate for the first two fidelities and must keep refusing on the third." @@ -68,6 +76,8 @@ fn primitive_projection_roster() -> List { primitive_projection_row(primitive: primitive_concept_decl_facts, module_path: "v2.std.concept_index", decl_name: "concept_decl_facts", fidelity: HostRealizedSeam), primitive_projection_row(primitive: primitive_concept_decl_facts_live, module_path: "v2.std.concept_index", decl_name: "concept_decl_facts_live", fidelity: HostRealizedSeam), primitive_projection_row(primitive: primitive_empty_map, module_path: "v2.std.collection", decl_name: "empty_map_primitive_delegate", fidelity: HostRealizedSeam), + primitive_projection_row(primitive: primitive_symbol_lexeme, module_path: "v2.std.compilers.lexing", decl_name: "symbol_lexeme", fidelity: HostRealizedSeam), + primitive_projection_row(primitive: primitive_symbol_intern_lexeme, module_path: "v2.std.compilers.lexing", decl_name: "symbol_intern_lexeme", fidelity: HostRealizedSeam), primitive_projection_row(primitive: primitive_length, module_path: "v2.std.algebra", decl_name: "length", fidelity: ModeledProjection), primitive_projection_row(primitive: primitive_map_insert, module_path: "v2.std.collection", decl_name: "map_insert", fidelity: ModeledProjection), primitive_projection_row(primitive: primitive_empty_map, module_path: "v2.std.collection", decl_name: "empty_map", fidelity: ModeledProjection), diff --git a/src/v1/runtime_rust.dag b/src/v1/runtime_rust.dag index db4279d885b..ce5622ce922 100644 --- a/src/v1/runtime_rust.dag +++ b/src/v1/runtime_rust.dag @@ -117,6 +117,18 @@ fn rt_string_ops() -> String { "pub fn string_length(s: &str) -> i64 {\n", " if s.is_ascii() { s.len() as i64 } else { s.chars().count() as i64 }\n", "}\n\n", + "/// The two symbol bridges. `Symbol` is declared to realize as `String` on this target\n", + "/// (extdeps.languages.rust.types), so interning and its inverse are both the identity\n", + "/// HERE and nowhere else: a target whose Symbol is a table index needs a real table, and\n", + "/// its registry rows would say so. These exist because the .dag declarations are\n", + "/// self-calls -- host seams -- and emitting a self-call produces a function that compiles\n", + "/// and never returns (std.primitive_projection symbol_lexeme_seam_disposition_note).\n", + "pub fn symbol_lexeme(sym: String) -> String {\n", + " sym\n", + "}\n\n", + "pub fn symbol_intern_lexeme(lexeme: String) -> String {\n", + " lexeme\n", + "}\n\n", "/// See `char_at`: the ASCII fast path is bounded by `end`, not by the whole string.\n", "pub fn substring(s: &str, start: i64, end: i64) -> String {\n", " let start = start.max(0) as usize;\n", From f17c17b43d2cedd6ea9f21fe7378a340b2957043 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 05:24:46 +0000 Subject: [PATCH 05/30] Regenerate the stage0 mirror for the emitter repairs (fixed point at round 2) Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- src/v1/stage0/src/v1_compiler_compile.rs | 5 +- src/v1/stage0/src/v1_compiler_emit_rust.rs | 68 +++++++++++++++---- src/v1/stage0/src/v1_compiler_infer.rs | 6 ++ src/v1/stage0/src/v1_compiler_infer_lookup.rs | 24 ++++--- src/v1/stage0/src/v1_compiler_infer_sigs.rs | 9 +-- src/v1/stage0/src/v1_std_core.rs | 7 ++ 6 files changed, 86 insertions(+), 33 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_compile.rs b/src/v1/stage0/src/v1_compiler_compile.rs index 14f64102b59..ed809719284 100644 --- a/src/v1/stage0/src/v1_compiler_compile.rs +++ b/src/v1/stage0/src/v1_compiler_compile.rs @@ -752,10 +752,7 @@ pub fn var_binding_kind_name(value: Rc) -> String { pub fn serialize_call_target_identity(value: Rc) -> String { match (*value.clone()).clone() { - CallTargetIdentity::RuntimePrimitiveCall { - primitive_name: primitive_name, - .. - } => v1_rt::concat( + CallTargetIdentity::RuntimePrimitiveCall { primitive_name, .. } => v1_rt::concat( v1_rt::concat( "{\"kind\": \"RuntimePrimitiveCall\", \"primitive_name\": ".to_string(), crate::v1_compiler_dag_collect_support::json_quote(primitive_name.clone()), diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 63b56370a23..8fb74c5ea3f 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -221,9 +221,10 @@ pub use crate::v1_std_core::{ transport_stdin, transport_tls_posture, tuple_type_name, with_required_cardinality, }; pub use crate::v1_std_core::{ - CallSemantics, CallTargetIdentity, Cardinality, CompilerDiagnostic, Connective, ErrorNode, - ExprData, FieldAccessStyle, FieldSummary, FieldValueShape, InferredNode, MatchPattern, - MethodSemantics, NewlineIndex, Node, StringPart, TextFile, UnaryOpKind, VarBindingKind, + CallSemantics, CallTargetIdentity, Cardinality, CompilerDiagnostic, Connective, + DeclaredCallableIdentity, ErrorNode, ExprData, FieldAccessStyle, FieldSummary, FieldValueShape, + InferredNode, MatchPattern, MethodSemantics, NewlineIndex, Node, StringPart, TextFile, + UnaryOpKind, VarBindingKind, }; use crate::NonEmptyBTreeSet; use crate::NonEmptyVec; @@ -20684,10 +20685,9 @@ pub fn call_semantics_target(cs: Option>) -> Rc) -> Option { match (*target.clone()).clone() { - CallTargetIdentity::RuntimePrimitiveCall { - primitive_name: primitive_name, - .. - } => Some(primitive_name.clone()), + CallTargetIdentity::RuntimePrimitiveCall { primitive_name, .. } => { + Some(primitive_name.clone()) + } CallTargetIdentity::SourceDeclarationCall { .. } => None, CallTargetIdentity::CallableTargetUndetermined => None, } @@ -20697,6 +20697,23 @@ pub fn call_target_is_runtime_primitive(target: Rc) -> bool (call_target_runtime_primitive_name(target.clone()) != None) } +pub fn call_target_projected_declaration( + target: Rc, +) -> Option> { + match (*target.clone()).clone() { + CallTargetIdentity::RuntimePrimitiveCall { projected_from, .. } => projected_from.clone(), + CallTargetIdentity::SourceDeclarationCall { .. } => None, + CallTargetIdentity::CallableTargetUndetermined => None, + } +} + +pub fn rust_runtime_primitive_has_bridge(primitive_name: String) -> bool { + v1_rt::map_contains_key( + &crate::extdeps_languages_rust_emit::rt_functions(), + primitive_name.clone(), + ) +} + pub fn emit_rust_expr_call( expr: Rc, registry: Rc>>, @@ -22242,7 +22259,8 @@ pub fn emit_typed_call( Some(primitive_name) => primitive_name.clone(), None => "".to_string(), }; - let is_rt = ((callee_is_function_value.clone() == false) && target_is_runtime.clone()); + let is_rt = (((callee_is_function_value.clone() == false) && target_is_runtime.clone()) + && rust_runtime_primitive_has_bridge(runtime_primitive_name.clone())); let is_rt_ref_map = (is_rt.clone() && v1_rt::map_contains_key( &crate::extdeps_languages_rust_emit::rt_ref_map_functions(), @@ -22406,11 +22424,33 @@ pub fn emit_typed_call( ) } CallTargetIdentity::RuntimePrimitiveCall { - primitive_name: _, .. - } => crate::v1_compiler_emit::emit_error_expr( - "runtime call target lost its bridge identity".to_string(), - RenderTarget::Rust, - ), + primitive_name: unbridged_primitive, + projected_from, + .. + } => { + match projected_from.clone() { + Some(declared) => { + if (declared.owner_module_path.clone() == scope.module_name.clone()) { + crate::v1_compiler_emit::emit_ident( + declared.decl_name.clone(), + RenderTarget::Rust, + ) + } else { + v1_rt::concat(v1_rt::concat(v1_rt::concat("crate::".to_string(), crate::v1_compiler_emit_core_support::module_to_filename(declared.owner_module_path.clone())), "::".to_string()), crate::v1_compiler_emit::emit_ident(declared.decl_name.clone(), RenderTarget::Rust)) + } + } + None => crate::v1_compiler_emit::emit_error_expr( + v1_rt::concat( + v1_rt::concat( + "primitive ".to_string(), + unbridged_primitive.clone(), + ), + " has no v1_rt realization and no declaration to emit".to_string(), + ), + RenderTarget::Rust, + ), + } + } } }; let func_name = if callee_self_capture.clone() { @@ -25091,7 +25131,7 @@ if rust_method_template_result_wraps_in_rc(method_name.clone()) { raw.clone() } }, - None => emit_rust_generic_method_call(method_name.clone(), receiver.clone(), args.clone(), result_type.clone(), true, registry.clone(), scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone()), + None => emit_rust_generic_method_call(method_name.clone(), receiver.clone(), args.clone(), result_type.clone(), rust_runtime_primitive_has_bridge(method_name.clone()), registry.clone(), scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone()), } } } diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 7031b6e1a70..79504f5b9fa 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -8411,6 +8411,7 @@ crate::v1_compiler_infer_types::resolve_type_variables_from_template(t.clone(), call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { primitive_name: "empty_map".to_string(), + projected_from: None, }), })), descent_evidence: None, @@ -8428,6 +8429,7 @@ match bare_m.clone() { call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { primitive_name: "empty_map".to_string(), + projected_from: None, }), })), descent_evidence: None, @@ -8441,6 +8443,7 @@ match bare_m.clone() { call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { primitive_name: "empty_map".to_string(), + projected_from: None, }), })), descent_evidence: None, @@ -8459,6 +8462,7 @@ match bare_m.clone() { call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { primitive_name: "empty_map".to_string(), + projected_from: None, }), })), descent_evidence: None, @@ -8472,6 +8476,7 @@ match bare_m.clone() { call_semantics: Some(Rc::new(CallSemantics::PlainCallSemantics { target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { primitive_name: "empty_map".to_string(), + projected_from: None, }), })), descent_evidence: None, @@ -8569,6 +8574,7 @@ let call_semantics = if (func_name.clone() == "lookup".to_string()) { Some(Rc::new(CallSemantics::LookupCallSemantics { target: Rc::new(CallTargetIdentity::RuntimePrimitiveCall { primitive_name: func_name.clone(), + projected_from: None, }), })) } else { diff --git a/src/v1/stage0/src/v1_compiler_infer_lookup.rs b/src/v1/stage0/src/v1_compiler_infer_lookup.rs index 6d37b016ff2..714d8300bf7 100644 --- a/src/v1/stage0/src/v1_compiler_infer_lookup.rs +++ b/src/v1/stage0/src/v1_compiler_infer_lookup.rs @@ -53,8 +53,7 @@ pub use crate::v1_compiler_infer_sigs::{ decide_callable_candidates, lookup_resolved_sig, parent_closure_callable_candidates, }; pub use crate::v1_compiler_infer_sigs::{ - CallableCandidate, CallableIdentity, DeclaredCallableIdentity, FuncSigLookup, ResolvedFuncEnv, - ResolvedFuncSig, + CallableCandidate, CallableIdentity, FuncSigLookup, ResolvedFuncEnv, ResolvedFuncSig, }; pub use crate::v1_compiler_infer_types::{ child_type_node, emit_map_has, enrich_kernel_type, instantiate_algebra_type, @@ -81,8 +80,9 @@ pub use crate::v1_std_core::{ with_required_cardinality, }; pub use crate::v1_std_core::{ - CallTargetIdentity, Cardinality, Connective, ErrorNode, FieldAccessStyle, FieldSummary, - FieldValueShape, InferredNode, MethodSemantics, NewlineIndex, Node, + CallTargetIdentity, Cardinality, Connective, DeclaredCallableIdentity, ErrorNode, + FieldAccessStyle, FieldSummary, FieldValueShape, InferredNode, MethodSemantics, NewlineIndex, + Node, }; use crate::NonEmptyBTreeSet; use crate::NonEmptyVec; @@ -209,6 +209,7 @@ pub fn resolved_declaration_call_target( crate::std_primitive_projection::primitive_identity_runtime_name( row.primitive.clone(), ), + projected_from: None, }) } ProjectionFidelity::ModeledProjection => { @@ -217,6 +218,7 @@ pub fn resolved_declaration_call_target( crate::std_primitive_projection::primitive_identity_runtime_name( row.primitive.clone(), ), + projected_from: Some(declared.clone()), }) } ProjectionFidelity::DivergentProjection { divergence: _, .. } => { @@ -252,6 +254,7 @@ pub fn builtin_call_target_or_undetermined(func_name: String) -> Rc Rc::new(CallTargetIdentity::RuntimePrimitiveCall { primitive_name: func_name.clone(), + projected_from: None, }), None => Rc::new(CallTargetIdentity::CallableTargetUndetermined), } @@ -267,7 +270,7 @@ pub fn callable_lookup_over_candidates( sig: sig.clone(), declared: Rc::new(DeclaredCallableIdentity { owner_module_path: func_env.name.clone(), - decl_name: name.clone(), + decl_name: crate::v1_std_core::qualified_last_segment(name.clone()), }), }), None => { @@ -616,7 +619,7 @@ pub fn borrowed_census_callable_candidate( identity: Rc::new(CallableIdentity::DeclaredCallable { identity: Rc::new(DeclaredCallableIdentity { owner_module_path: candidate.module_path.clone(), - decl_name: name.clone(), + decl_name: crate::v1_std_core::qualified_last_segment(name.clone()), }), }), sig: Rc::new(ResolvedFuncSig { @@ -699,7 +702,9 @@ pub fn func_sig_from_global_bare(type_env: Rc, name: String) -> Rc, name: String) -> Rc, } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -pub struct DeclaredCallableIdentity { - pub owner_module_path: String, - pub decl_name: String, -} - #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(tag = "_variant")] pub enum CallableIdentity { diff --git a/src/v1/stage0/src/v1_std_core.rs b/src/v1/stage0/src/v1_std_core.rs index d2c7bac19b7..cb83f6cf7c0 100644 --- a/src/v1/stage0/src/v1_std_core.rs +++ b/src/v1/stage0/src/v1_std_core.rs @@ -229,11 +229,18 @@ impl VarBindingKind { } } +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct DeclaredCallableIdentity { + pub owner_module_path: String, + pub decl_name: String, +} + #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] #[serde(tag = "_variant")] pub enum CallTargetIdentity { RuntimePrimitiveCall { primitive_name: String, + projected_from: Option>, }, SourceDeclarationCall { owner_module_path: String, From c5de5aae6cbd6adf67230048f99a36f938abffd8 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 05:39:04 +0000 Subject: [PATCH 06/30] test.claim fixtures: one discriminating RED per closed emission class, with boundary controls Six rows over the three emitter defects plus the two symbol bridges. Each class's positive and negative assertion differ only in the fact the repair added, so no single edit satisfies both directions, and each repair carries a boundary control that would go red had it over-reached the other way (empty_map for the registry gate, a registered bridge method for the class-B gate). The symbol-bridge row is deliberately not an error-count assertion: that class COMPILED throughout the defect and diverged by not terminating, so a row asserting 'no error' would have been green the whole time. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...d_call_target_realization_witness_test.dag | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 dag/test/claim/emitted_call_target_realization_witness_test.dag diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag new file mode 100644 index 00000000000..2a69a859d6d --- /dev/null +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -0,0 +1,91 @@ +module test.claim.emitted_call_target_realization_witness_test + +import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } + +data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly + +data emitted_call_target_realization_witness_note: String = "PERMANENT REGRESSION CONTROLS for the three emission defects that stood between the v2 compiler closure and a Rust crate rustc would accept (gunbc#9664 milestones 1 and 2). All three are one family -- emission ASSERTING a realization it had not established -- and each row here is the discriminating RED for one of them, paired with a boundary control that would go red if the repair had over-reached in the opposite direction.\n\nMEASURED POPULATIONS on the emitted closure at main 6447dd4, by `gunbc compile --entry src/v2/compiler/00_compile.dag --target rust` then `cargo check`: 260 coded errors, 254 of them E0425. Class C 102 (98 `v2` + 4 `std`), length 73, class B 65 (member 11, apply 11, is_empty 5, allocate_literal 4, step 3, init 3, and a tail of ones and twos).\n\nWHY THESE ARE NOT A SNAPSHOT. Each class's positive and negative assertion differ only in the fact the repair added, so no single edit satisfies both directions. The C rows would flip if decl_name reverted to the authored spelling; the length rows would flip if the registry membership gate were removed OR if the declaration fallback were extended to seams; the B rows would flip if runtime_bridge went back to a literal. The boundary controls (empty_map, a real bridge method) would flip if any of the three repairs had instead stopped emission reaching v1_rt at all.\n\nDISSOLVE-ON: never. Emission may change target SPELLING, but it may never again name a runtime symbol it has not established exists."; + +// CLASS C, THE DISCRIMINATING RED. A qualified call carried the whole dotted path as its +// declaration name, so emission produced `crate::v2_std_collection::v2.std.collection.map_get(..)` +// -- the module prefix correct and the identifier a dotted path Rust reads as field access on an +// undefined value `v2`. map_get is the specimen because it is also DivergentProjection, so this +// row proves the qualified path reaches the DECLARATION and not the bridge. +test fn w_qualified_call_emits_only_the_declaration_last_segment() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.qualified_call_probe\nimport std.types { Int, String, Map }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.diagnostic { Outcome }\nimport v2.std.optional { Optional }\nfn probe(m: Map) -> Outcome> { v2.std.collection.map_get(m: m, key: \"key\") }\n", + "src/test_claim_qualified_call_probe.rs", + ["crate::v2_std_collection::map_get("], + ["::v2.std.collection", "v2.std.collection.map_get("] + ) +} + +// LENGTH, THE DISCRIMINATING RED. v2.std.algebra length is a ModeledProjection of the `length` +// primitive and rt_function_registry has no `length` row, so emission took the identity arm of +// rust_runtime_bridge_name and wrote `v1_rt::length` -- a symbol the seed does not define -- at +// 73 sites. The declaration has a real fold body, so it is what a call must reach. +test fn w_unbridged_modeled_primitive_emits_its_declaration() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.length_projection_probe\nimport std.types { Int }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.algebra { FreeMonoid, length }\nfn probe(xs: FreeMonoid) -> Int { length(xs: xs) }\n", + "src/test_claim_length_projection_probe.rs", + ["crate::v2_std_algebra::length("], + ["v1_rt::length("] + ) +} + +// THE BOUNDARY CONTROL FOR THE LENGTH REPAIR, AND THE ONE THAT PROVES THE GATE IS REGISTRY +// MEMBERSHIP RATHER THAN "ROSTER ROW MEANS DECLARATION". empty_map has a roster row AND a +// registry row, so it must still lower to the bridge. A repair that had simply routed every +// ModeledProjection to its declaration would go red here -- and would also emit +// v2.std.collection map_insert's `Map { lookup: fn .. }` body against an Rc carrier. +test fn w_bridged_modeled_primitive_still_lowers_to_the_bridge() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.bridged_empty_map_probe\nimport std.types { Int, String, Map }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.collection { empty_map }\nfn probe() -> Map { empty_map() }\n", + "src/test_claim_bridged_empty_map_probe.rs", + ["v1_rt::rc_empty_map"], + ["crate::v2_std_collection::empty_map("] + ) +} + +// CLASS B, THE DISCRIMINATING RED. tier0 method resolution resolves an ordinary fn-typed RECORD +// FIELD through lookup_field_in_product, so a field call arrived as AlgebraMethodSemantics and the +// fallback at the end of that arm passed runtime_bridge: true unconditionally -- emitting +// `v1_rt::step`, and leaving emit_rust_generic_method_call's own callable-field arm, guarded on +// runtime_bridge == false, unreachable for the exact receiver it was written for. +test fn w_callable_record_field_lowers_as_a_field_not_a_bridge() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.callable_field_probe\nimport std.types { Int }\ntype Stepper { step: fn(Int) -> Int }\nfn probe(s: Stepper, n: Int) -> Int { s.step(n) }\n", + "src/test_claim_callable_field_probe.rs", + [".step)("], + ["v1_rt::step("] + ) +} + +// THE BOUNDARY CONTROL FOR THE B REPAIR. `count` IS in rt_function_registry, so method-form calls +// that genuinely name a bridge must still reach one. A repair that had stopped the algebra +// fallback reaching v1_rt at all -- rather than asking whether this particular name is realized -- +// goes red here. +test fn w_registered_bridge_method_still_reaches_the_bridge() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.bridge_method_probe\nimport std.types { Int, List }\nfn probe(xs: List) -> Int { xs |> count }\n", + "src/test_claim_bridge_method_probe.rs", + ["v1_rt::count("], + ["compile_error"] + ) +} + +// THE SYMBOL BRIDGES, AND THIS ONE'S RED IS NOT AN ERROR COUNT. symbol_lexeme and +// symbol_intern_lexeme have self-call bodies -- host seams -- but carried no projection roster +// row, so the resolver saw ordinary declarations and emission emitted the declaration. The result +// COMPILES: `pub fn symbol_lexeme(sym: String) -> String { symbol_lexeme(sym) }` type-checks and +// never returns. That is why these two are absent from the E0425 census this file's other rows +// are measured against -- they were silent, not absent. A row asserting "no error" would have +// been green throughout the defect; this asserts the call reaches the realization. +test fn w_symbol_lexeme_reaches_its_host_realization_not_its_self_call() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.symbol_lexeme_probe\nimport std.types { String }\nimport v2.std.node { Symbol }\nimport v2.std.compilers.lexing { symbol_lexeme }\nfn probe(sym: Symbol) -> String { symbol_lexeme(sym: sym) }\n", + "src/test_claim_symbol_lexeme_probe.rs", + ["v1_rt::symbol_lexeme("], + ["crate::v2_std_compilers_lexing::symbol_lexeme("] + ) +} From f8ea19f649299fd0010ada856466623f798fbfd8 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 05:40:04 +0000 Subject: [PATCH 07/30] Fix the class-B boundary control: count has a method template, so it never reaches the seam under repair count is answered by rust_simple_method_specs before the algebra fallback, so the row would have gone red while executing none of the code the repair touched. trim is in rt_function_registry and has no template, so it is one of the few names that actually reaches that fallback. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...ed_call_target_realization_witness_test.dag | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 2a69a859d6d..4b0848cd60a 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -61,15 +61,21 @@ test fn w_callable_record_field_lowers_as_a_field_not_a_bridge() -> Bool { ) } -// THE BOUNDARY CONTROL FOR THE B REPAIR. `count` IS in rt_function_registry, so method-form calls -// that genuinely name a bridge must still reach one. A repair that had stopped the algebra -// fallback reaching v1_rt at all -- rather than asking whether this particular name is realized -- -// goes red here. +// THE BOUNDARY CONTROL FOR THE B REPAIR. `trim` is in rt_function_registry and, unlike count / +// join / first and the rest of rust_simple_method_specs, has NO method template -- so it is one of +// the few names that actually REACHES the algebra fallback this repair changed. A repair that had +// stopped that fallback reaching v1_rt at all, rather than asking whether this particular name is +// realized, goes red here. +// +// count was the first choice for this row and is wrong, which is worth recording: it has a +// template (`(\{recv\}.len() as i64)`), so it is answered before the fallback and would have gone +// red while testing nothing about the seam under repair -- a control passing through a codepath +// its subject never executes. test fn w_registered_bridge_method_still_reaches_the_bridge() -> Bool { compile_dag_rust_emit_check( - "module test.claim.bridge_method_probe\nimport std.types { Int, List }\nfn probe(xs: List) -> Int { xs |> count }\n", + "module test.claim.bridge_method_probe\nimport std.types { String }\nfn probe(s: String) -> String { s |> trim }\n", "src/test_claim_bridge_method_probe.rs", - ["v1_rt::count("], + ["v1_rt::trim("], ["compile_error"] ) } From 73a1aa495bdd6651cab88e0ed380eeec9f8eae98 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 05:52:54 +0000 Subject: [PATCH 08/30] Unbreak the fixture parse: a trailing semicolon on the note declaration The module index refused the file outright, so none of the six witnesses were discovered. .dag item declarations carry no terminator. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- .../emitted_call_target_realization_witness_test.dag | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 4b0848cd60a..0fc160439b2 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -4,7 +4,7 @@ import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly } data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly -data emitted_call_target_realization_witness_note: String = "PERMANENT REGRESSION CONTROLS for the three emission defects that stood between the v2 compiler closure and a Rust crate rustc would accept (gunbc#9664 milestones 1 and 2). All three are one family -- emission ASSERTING a realization it had not established -- and each row here is the discriminating RED for one of them, paired with a boundary control that would go red if the repair had over-reached in the opposite direction.\n\nMEASURED POPULATIONS on the emitted closure at main 6447dd4, by `gunbc compile --entry src/v2/compiler/00_compile.dag --target rust` then `cargo check`: 260 coded errors, 254 of them E0425. Class C 102 (98 `v2` + 4 `std`), length 73, class B 65 (member 11, apply 11, is_empty 5, allocate_literal 4, step 3, init 3, and a tail of ones and twos).\n\nWHY THESE ARE NOT A SNAPSHOT. Each class's positive and negative assertion differ only in the fact the repair added, so no single edit satisfies both directions. The C rows would flip if decl_name reverted to the authored spelling; the length rows would flip if the registry membership gate were removed OR if the declaration fallback were extended to seams; the B rows would flip if runtime_bridge went back to a literal. The boundary controls (empty_map, a real bridge method) would flip if any of the three repairs had instead stopped emission reaching v1_rt at all.\n\nDISSOLVE-ON: never. Emission may change target SPELLING, but it may never again name a runtime symbol it has not established exists."; +data emitted_call_target_realization_witness_note: String = "PERMANENT REGRESSION CONTROLS for the three emission defects that stood between the v2 compiler closure and a Rust crate rustc would accept (gunbc#9664 milestones 1 and 2). All three are one family -- emission ASSERTING a realization it had not established -- and each row here is the discriminating RED for one of them, paired with a boundary control that would go red if the repair had over-reached in the opposite direction.\n\nMEASURED POPULATIONS on the emitted closure at main 6447dd4, by `gunbc compile --entry src/v2/compiler/00_compile.dag --target rust` then `cargo check`: 260 coded errors, 254 of them E0425. Class C 102 (98 `v2` + 4 `std`), length 73, class B 65 (member 11, apply 11, is_empty 5, allocate_literal 4, step 3, init 3, and a tail of ones and twos).\n\nWHY THESE ARE NOT A SNAPSHOT. Each class's positive and negative assertion differ only in the fact the repair added, so no single edit satisfies both directions. The C rows would flip if decl_name reverted to the authored spelling; the length rows would flip if the registry membership gate were removed OR if the declaration fallback were extended to seams; the B rows would flip if runtime_bridge went back to a literal. The boundary controls (empty_map, a real bridge method) would flip if any of the three repairs had instead stopped emission reaching v1_rt at all.\n\nDISSOLVE-ON: never. Emission may change target SPELLING, but it may never again name a runtime symbol it has not established exists." // CLASS C, THE DISCRIMINATING RED. A qualified call carried the whole dotted path as its // declaration name, so emission produced `crate::v2_std_collection::v2.std.collection.map_get(..)` @@ -68,9 +68,9 @@ test fn w_callable_record_field_lowers_as_a_field_not_a_bridge() -> Bool { // realized, goes red here. // // count was the first choice for this row and is wrong, which is worth recording: it has a -// template (`(\{recv\}.len() as i64)`), so it is answered before the fallback and would have gone -// red while testing nothing about the seam under repair -- a control passing through a codepath -// its subject never executes. +// simple-method template, so it is answered before the fallback and would have gone red while +// testing nothing about the seam under repair -- a control passing through a codepath its +// subject never executes. test fn w_registered_bridge_method_still_reaches_the_bridge() -> Bool { compile_dag_rust_emit_check( "module test.claim.bridge_method_probe\nimport std.types { String }\nfn probe(s: String) -> String { s |> trim }\n", From c92b6702d87c08db04c27f60aed773eae9bfbec4 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 06:07:20 +0000 Subject: [PATCH 09/30] The self-call seam wall: an unrealized host seam refuses instead of emitting compiling recursion A whole-body self-call is the decidable structural marker of a host seam. In the interpreter the shape is safe -- reaching it recurses to the evaluation-budget refusal -- but emitted to Rust the same shape COMPILES and returns to no caller. Nothing reported it: not the module index, not the compile-clean gate, not cargo check. That is why the two symbol bridges were invisible until someone read the emitted bytes. emit_fn_def now asks the realization registry -- the same authority the call sites ask, so the two cannot drift -- and suppresses the declaration when the seam is realized, refuses with a located message when it is not. Suppression rather than delegation is deliberate: a forwarding body would make this seam reconstruct signatures in target types, which is the cementing the existing suppressed-seam precedent avoids, and a realized primitive's calls all route to the bridge anyway. The predicate is whole-body identity, not 'contains a self-call'. Ordinary recursion has a match, an if or a let between the head and the call, so it never matches; expr_has_self_call walks children and would have refused most of the compiler. Both directions carry a fixture. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...d_call_target_realization_witness_test.dag | 30 +++++++++++ src/v1/05_emit_rust.dag | 54 +++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 0fc160439b2..277f757c0ce 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -95,3 +95,33 @@ test fn w_symbol_lexeme_reaches_its_host_realization_not_its_self_call() -> Bool ["crate::v2_std_compilers_lexing::symbol_lexeme("] ) } + +// THE SELF-CALL SEAM WALL, AND THIS IS THE ROW THAT MAKES THE CLASS STRUCTURAL RATHER THAN +// ROSTERED. Adding a self-calling declaration with no target realization used to emit it verbatim: +// `pub fn f(x) { f(x) }` compiles, and returns to no caller. Nothing reported it -- not the module +// index, not the compile-clean gate, not cargo check -- which is why the two symbol bridges were +// invisible until someone read the emitted bytes. The refusal now fires on the STRUCTURE, so a new +// seam cannot be added silently even if nobody remembers to roster it. +// +// The discriminating pair is the declaration itself: pre-wall the emitted module carries +// `pub fn declared_seam_without_realization`, post-wall it carries the refusal instead. +test fn w_unrealized_self_call_seam_refuses_instead_of_emitting_recursion() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.unrealized_seam_probe\nimport std.types { String }\nfn declared_seam_without_realization(x: String) -> String { declared_seam_without_realization(x: x) }\nfn probe(x: String) -> String { declared_seam_without_realization(x: x) }\n", + "src/test_claim_unrealized_seam_probe.rs", + ["has no realization for this target"], + ["pub fn declared_seam_without_realization"] + ) +} + +// ORDINARY RECURSION IS NOT A SEAM, and this is the control that keeps the wall from refusing most +// of the compiler. The predicate is whole-body identity, not "contains a self-call": a match, an if +// or a let between the head and the recursive call means the body is not the call. +test fn w_ordinary_recursion_is_not_read_as_a_host_seam() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.ordinary_recursion_probe\nimport std.types { Int }\nfn countdown(n: Int) -> Int { if n <= 0 { 0 } else { countdown(n: n - 1) } }\n", + "src/test_claim_ordinary_recursion_probe.rs", + ["pub fn countdown"], + ["has no realization for this target"] + ) +} diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index fdcd70afe2d..b89fe080a5a 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -7201,6 +7201,53 @@ fn v1_call_site_equality_forwarded_param_names( } } +// A WHOLE-BODY SELF-CALL IS THE STRUCTURAL MARKER OF A HOST SEAM, AND IT IS DECIDABLE. +// +// `fn decl_facts(pool_roots) { decl_facts(pool_roots: pool_roots) }` is not recursion that happens +// to be unbounded -- it is a declaration saying "my body lives in the host", and reaching it in the +// interpreter recurses to the evaluation-budget refusal, which is why the shape is safe there. In +// EMITTED RUST it is not safe: the same shape compiles, and the resulting function returns to no +// caller. That is DESIGN section 5 silent wrongness, and it is strictly worse than the unresolved +// symbol a missing bridge produces, because nothing anywhere reports it. The two symbol bridges sat +// in exactly this state and were absent from every error census precisely because they were silent. +// +// THE TEST IS THE WHOLE BODY, NOT A CONTAINED CALL. Ordinary recursion has a match, an if, or a let +// between the head and the self-call, so it never matches; expr_has_self_call, which walks children, +// is the wrong predicate here and would refuse most of the compiler. This asks only whether the body +// IS the self-call. +fn rust_body_is_bare_self_call(name: String, body: Node, source_indices: Map) -> Bool { + match body.expr_data { + ExprCall { call_semantics: _, descent_evidence: _ } => + qualified_last_segment(name: expr_call_func_at(texpr: body, source_indices: source_indices)) == name + _ => false + } +} + +// THE SEAM'S DISPOSITION AT THIS TARGET, ASKED OF THE REALIZATION REGISTRY RATHER THAN A NAME +// LITERAL. rust_host_string_seam_fn_emit above answers for two seams by spelling their Rust bodies +// out in the emitter, which is both hand-written target code in a compiler stage and a bare-name +// key. This asks the same registry the CALL SITES ask, so a seam's declaration is suppressed here +// exactly when a call to it lowers to a bridge, and the two answers cannot drift. +// +// SUPPRESSION, NOT DELEGATION, IS THE REALIZED ARM. Emitting a forwarding body would require this +// seam to reconstruct the signature in target types, which is the cementing the suppressed +// precedent avoids; and the declaration has no honest caller anyway, because every call to a +// realized primitive routes to the bridge. If some path ever misses that routing, the result is an +// unresolved symbol -- loud, located, and fixable -- rather than a silent nonterminating call. +fn rust_host_seam_declaration_emit(name: String, body: Node, source_indices: Map) -> String? { + if rust_body_is_bare_self_call(name: name, body: body, source_indices: source_indices) == false { + none + } else if rust_runtime_primitive_has_bridge(primitive_name: name) { + Present { value: "" } + } else { + Present { value: concat( + "compile_error!(\"host seam '", name, "' has no realization for this target: its whole body is a self-call, ", + "so emitting it would produce a compiling, nonterminating function. Give it a row in ", + "extdeps.languages.rust.emit rt_function_registry and a body in v1.runtime_rust.\");\n" + ) } + } +} + fn emit_fn_def(name: String, params: List, inferred: Node, body: Node, registry: Map, scope: InferScope, shared_types: Set, emit_info: EmitGraphInfo) -> String { let si = scope.type_env.source_indices let host_text_op = rust_host_string_op_fn_emit(name: name) @@ -7210,6 +7257,13 @@ fn emit_fn_def(name: String, params: List, inferred: Node, body: Node, reg Absent => "" } } + let host_seam_emit = rust_host_seam_declaration_emit(name: name, body: body, source_indices: si) + if host_seam_emit != none { + return match host_seam_emit { + Present { value: seam_emit } => seam_emit + Absent => "" + } + } match rust_host_string_seam_fn_emit(name: name) { Present { value: seam_fn } => { let _unused = seam_fn "" } From 7a0577cd1f6153c6f71c8b85f227f03f42a76545 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 07:37:03 +0000 Subject: [PATCH 10/30] The seam wall must resolve realization through the roster's primitive, not the declaration name Measured, not predicted: the wall refused six seams in the emitted closure and one of them -- v2.std.collection empty_map_primitive_delegate -- is realized. Its roster row names the empty_map primitive, whose bridge is rc_empty_map, but rt_function_registry holds 'empty_map' and the wall looked up 'empty_map_primitive_delegate'. A declaration's name and the primitive it realizes are two facts; the roster is the authority that joins them, and the declaration name is only the fallback for a seam nobody has rostered. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...d_call_target_realization_witness_test.dag | 19 +++++++++++++++ src/v1/05_emit_rust.dag | 24 ++++++++++++++++--- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 277f757c0ce..7e94f844812 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -125,3 +125,22 @@ test fn w_ordinary_recursion_is_not_read_as_a_host_seam() -> Bool { ["has no realization for this target"] ) } + +// A SEAM'S DECLARATION NAME IS NOT THE PRIMITIVE IT REALIZES, and this row is the one that caught +// it. v2.std.collection empty_map_primitive_delegate is a self-call body -- so the wall sees a seam +// -- and it IS realized, because its roster row names the `empty_map` primitive whose bridge is +// rc_empty_map. Keying the realization lookup on the DECLARATION name missed, because the registry +// holds `empty_map`, and the wall refused a seam that had a perfectly good realization. Measured, +// not predicted: it appeared as one of six refusals in the emitted closure. +// +// The discriminating direction is that this seam must NOT refuse while decl_facts, which genuinely +// has no realization, must. A wall that reverted to decl-name keying flips this row red and leaves +// the decl_facts row green, so the two cannot be satisfied by one edit. +test fn w_rostered_seam_resolves_realization_through_its_primitive_not_its_decl_name() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.delegate_seam_probe\nimport std.types { Int, String, Map }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.collection { empty_map }\nfn probe() -> Map { empty_map() }\n", + "src/test_claim_delegate_seam_probe.rs", + ["v1_rt::rc_empty_map"], + ["has no realization for this target"] + ) +} diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index b89fe080a5a..cecb593efd1 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -1,6 +1,10 @@ module v1.compiler.emit_rust import std.occurrence_identity { OccurrenceSynthetic } +import std.decl_ref { decl_ref } +import std.primitive_projection { + primitive_identity_runtime_name, primitive_projection_row_for_declaration +} import extdeps.languages.rust.capabilities { phantom_opaque_carrier_derive_traits } @@ -7234,10 +7238,24 @@ fn rust_body_is_bare_self_call(name: String, body: Node, source_indices: Map) -> String? { +// THE PRIMITIVE A DECLARATION PROJECTS, WHICH IS NOT ITS OWN NAME. A seam's declaration name and +// the primitive it realizes are different facts, and keying realization on the declaration name +// was a defect measured rather than reasoned: v2.std.collection empty_map_primitive_delegate is +// rostered to the `empty_map` primitive, whose bridge is rc_empty_map, so it IS realized -- but the +// registry holds `empty_map`, not `empty_map_primitive_delegate`, so a decl-name lookup missed and +// the wall refused a seam that had a perfectly good realization. The roster is the authority that +// joins the two; the declaration name is only the fallback for a seam nobody has rostered. +fn rust_seam_primitive_name(module_path: String, name: String) -> String { + match primitive_projection_row_for_declaration(declaration: decl_ref(module_path: module_path, decl_name: name)) { + Present { value: row } => primitive_identity_runtime_name(identity: row.primitive) + Absent => name + } +} + +fn rust_host_seam_declaration_emit(module_path: String, name: String, body: Node, source_indices: Map) -> String? { if rust_body_is_bare_self_call(name: name, body: body, source_indices: source_indices) == false { none - } else if rust_runtime_primitive_has_bridge(primitive_name: name) { + } else if rust_runtime_primitive_has_bridge(primitive_name: rust_seam_primitive_name(module_path: module_path, name: name)) { Present { value: "" } } else { Present { value: concat( @@ -7257,7 +7275,7 @@ fn emit_fn_def(name: String, params: List, inferred: Node, body: Node, reg Absent => "" } } - let host_seam_emit = rust_host_seam_declaration_emit(name: name, body: body, source_indices: si) + let host_seam_emit = rust_host_seam_declaration_emit(module_path: scope.module_name, name: name, body: body, source_indices: si) if host_seam_emit != none { return match host_seam_emit { Present { value: seam_emit } => seam_emit From 50b10e4f64195d9b45ff1664eb46d93c859ceb1f Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 08:46:26 +0000 Subject: [PATCH 11/30] The seam wall's realized arm must not suppress the declaration: suppression created 10 dangling imports Measured on the emitted closure with the wall finally in the mirror: removing a realized seam's item left 10 unresolved imports (E0432) for symbol_lexeme, symbol_intern_lexeme and resolve_type_node. Other modules import these declarations; the suppression created that breakage rather than finding it. And the reasoning that made suppression look safe is what makes it unnecessary. A realized seam's body IS a call to itself, and resolution already routes that call through the roster to the bridge -- so ordinary emission writes v1_rt::symbol_lexeme(sym) as the body without help. The wall's whole job is the UNREALIZED arm. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...ted_call_target_realization_witness_test.dag | 16 ++++++++++++++++ src/v1/05_emit_rust.dag | 17 +++++++++++------ 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 7e94f844812..a85db8c276d 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -144,3 +144,19 @@ test fn w_rostered_seam_resolves_realization_through_its_primitive_not_its_decl_ ["has no realization for this target"] ) } + +// A REALIZED SEAM KEEPS ITS DECLARATION, and this row exists because removing it was a defect I +// shipped. The wall first suppressed a realized seam's item, reasoning that every call to a +// realized primitive routes to the bridge so nothing calls the declaration. Other modules still +// IMPORT it, so 10 unresolved imports (E0432) appeared in the emitted closure -- created by the +// suppression, not found by it. The same reasoning that made suppression look safe is what makes +// it unnecessary: the seam's body is a self-call, resolution routes it through the roster to the +// bridge, and ordinary emission writes the delegation by itself. +test fn w_realized_seam_keeps_its_declaration_and_delegates_to_the_bridge() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.realized_seam_probe\nimport std.types { String }\nimport v2.std.node { Symbol }\nimport v2.std.compilers.lexing { symbol_lexeme }\nfn probe(sym: Symbol) -> String { symbol_lexeme(sym: sym) }\n", + "src/test_claim_realized_seam_probe.rs", + ["v1_rt::symbol_lexeme("], + ["has no realization for this target"] + ) +} diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index cecb593efd1..41a64519b5a 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -7233,11 +7233,16 @@ fn rust_body_is_bare_self_call(name: String, body: Node, source_indices: Map Date: Sat, 29 Aug 2026 08:49:23 +0000 Subject: [PATCH 12/30] The seam refusal is a generated body, not a crate-wide compile_error!: rustc's denominator is larger than the demand denominator compile_error! fails the WHOLE crate, and that form silently assumes every seam it refuses is one somebody calls. It is not. rustc type-checks the entire emitted crate including declarations imported but never invoked, so the refusal denominator is strictly larger than the entry-reachable execution closure -- five unreachable seams took the crate down. The refusal is now a panic body with the declaration's real signature: dependent modules resolve, the crate compiles, and only an actual invocation fails loudly. That moves the refusal from the crate to the one declaration that earned it, and leaves reachability to a separate instrument. An entry-rooted pruner can replace the body later without revisiting this. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...d_call_target_realization_witness_test.dag | 20 ++++++++- src/v1/05_emit_rust.dag | 41 ++++++++++--------- 2 files changed, 40 insertions(+), 21 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index a85db8c276d..5ea0b3fe224 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -109,8 +109,24 @@ test fn w_unrealized_self_call_seam_refuses_instead_of_emitting_recursion() -> B compile_dag_rust_emit_check( "module test.claim.unrealized_seam_probe\nimport std.types { String }\nfn declared_seam_without_realization(x: String) -> String { declared_seam_without_realization(x: x) }\nfn probe(x: String) -> String { declared_seam_without_realization(x: x) }\n", "src/test_claim_unrealized_seam_probe.rs", - ["has no realization for this target"], - ["pub fn declared_seam_without_realization"] + ["unrealized host seam", "panic!"], + ["declared_seam_without_realization(x)"] + ) +} + +// THE REFUSAL KEEPS THE SIGNATURE AND THE CRATE KEEPS COMPILING. This is the row that separates the +// two refusal FORMS, and it is the whole point of the correction: compile_error! fails the entire +// crate, which is wrong for a seam nobody calls, because rustc's denominator is the whole emitted +// crate while the demand denominator is the entry-reachable closure. Five unreachable seams took +// the crate down under the old form. The declaration must therefore still be emitted, with its +// parameters and return type intact, so that dependent modules resolve and only an actual call +// fails. +test fn w_unrealized_seam_refusal_preserves_the_declaration_signature() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.unrealized_seam_shape_probe\nimport std.types { String }\nfn seam_with_no_realization(x: String) -> String { seam_with_no_realization(x: x) }\n", + "src/test_claim_unrealized_seam_shape_probe.rs", + ["pub fn seam_with_no_realization", "-> String", "panic!"], + ["compile_error!"] ) } diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 41a64519b5a..e866e2f3baf 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -7233,6 +7233,16 @@ fn rust_body_is_bare_self_call(name: String, body: Node, source_indices: Map String { } } -fn rust_host_seam_declaration_emit(module_path: String, name: String, body: Node, source_indices: Map) -> String? { - if rust_body_is_bare_self_call(name: name, body: body, source_indices: source_indices) == false { - none - } else if rust_runtime_primitive_has_bridge(primitive_name: rust_seam_primitive_name(module_path: module_path, name: name)) { - none - } else { - Present { value: concat( - "compile_error!(\"host seam '", name, "' has no realization for this target: its whole body is a self-call, ", - "so emitting it would produce a compiling, nonterminating function. Give it a row in ", - "extdeps.languages.rust.emit rt_function_registry and a body in v1.runtime_rust.\");\n" - ) } - } +fn rust_host_seam_is_unrealized(module_path: String, name: String, body: Node, source_indices: Map) -> Bool { + rust_body_is_bare_self_call(name: name, body: body, source_indices: source_indices) + && rust_runtime_primitive_has_bridge(primitive_name: rust_seam_primitive_name(module_path: module_path, name: name)) == false } fn emit_fn_def(name: String, params: List, inferred: Node, body: Node, registry: Map, scope: InferScope, shared_types: Set, emit_info: EmitGraphInfo) -> String { @@ -7280,13 +7281,6 @@ fn emit_fn_def(name: String, params: List, inferred: Node, body: Node, reg Absent => "" } } - let host_seam_emit = rust_host_seam_declaration_emit(module_path: scope.module_name, name: name, body: body, source_indices: si) - if host_seam_emit != none { - return match host_seam_emit { - Present { value: seam_emit } => seam_emit - Absent => "" - } - } match rust_host_string_seam_fn_emit(name: name) { Present { value: seam_fn } => { let _unused = seam_fn "" } @@ -7365,6 +7359,15 @@ fn emit_fn_def(name: String, params: List, inferred: Node, body: Node, reg let depth = 0 let use_tco = is_tco_eligible(name: name, body: body, registry: registry, source_indices: si) let needs_stacker = is_self_recursive(name: name, body: body, registry: registry, source_indices: si) && use_tco == false + if rust_host_seam_is_unrealized(module_path: scope.module_name, name: name, body: body, source_indices: si) { + let kw = rust_items().func_keyword + return concat(rust_visibility_prefix(), kw, " ", emit_ident(name: name, target: Rust), type_params_str, "(", params_str, ")", ret_str, " {\n", + make_indent(level: 1), + "panic!(\"unrealized host seam '", name, "' in ", scope.module_name, + ": this declaration's whole body is a self-call, so it has no behaviour on this target. ", + "It compiles as a refusal rather than as recursion. Give it a row in ", + "extdeps.languages.rust.emit rt_function_registry and a body in v1.runtime_rust, or delete its consumers.\")\n}") + } if use_tco { let tco_params_str = emit_tco_params(params: value_params, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: si, variant_to_enum: emit_info.variant_to_enum, env: scope.type_env) let body_str = emit_typed_tco_body(texpr: body, fn_name: name, params: value_params, registry: registry, scope: body_scope, depth: depth + 1, shared_types: shared_types, emit_info: body_emit_info) From bd7dac664fbebe5ad810168feb904a7494fb1380 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 09:34:23 +0000 Subject: [PATCH 13/30] Two obligations the required floor found, both real consequences of this change DETERMINISM DENOMINATOR (9 reach_witness rows red, including determinism_denominator_is_closed_on_declared_primitives, whose entire job is to notice this). v2.lens.determinism closes its denominator over primitive_declared_definitions, so adding two canonical names without traversal facts made the closure false. Both bridges are scalar -- symbol_lexeme maps one Symbol to its text and symbol_intern_lexeme is its inverse -- so there is no collection to walk and OrderFreeResult is the honest arm. HostUnspecifiedOrder would claim a real traversal whose order the host does not pin, fabricating a leak the primitive cannot have. NAMESPACE WAVE ADMISSION (6 unadjudicated deltas). Four are TargetChanged for DeclaredCallableIdentity moving v1.compiler.infer_sigs -> v1.std.core, which is what lets CallTargetIdentity carry the declaration a runtime target was projected from. infer_sigs imports v1.std.core, so the type could not stay put without a cycle. Four enumerated rows, one per binding site; the two membership deltas auto-admit as ExplicitlyEvaluatedZeroDelta. Dissolve-on: this PR merging, by the same trigger the three prior shrinks record. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- dag/std/primitive_identity.dag | 18 ++++++ src/v1/stage0/src/namespace_wave_admission.rs | 61 ++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/dag/std/primitive_identity.dag b/dag/std/primitive_identity.dag index 157368375c9..0430947387c 100644 --- a/dag/std/primitive_identity.dag +++ b/dag/std/primitive_identity.dag @@ -31,6 +31,7 @@ import std.primitive_projection { primitive_length, primitive_map_insert, primitive_map_get, primitive_empty_map, primitive_decl_facts, primitive_export_signature_facts, primitive_data_decl_type_facts, primitive_concept_decl_facts, primitive_concept_decl_facts_live, + primitive_symbol_lexeme, primitive_symbol_intern_lexeme, } data primitive_identity_d0_scope_note: String = "D0 is NOT terminal acceptance and does NOT close the subject universe. Landed and executing: join mechanism across five carriers, five refusal variants typed, three refusal detectors executing with witnesses (see primitive_d0_refusal_execution_note), derived census across all five surfaces including InterpreterDispatch from gunbc.v1_interpreter_primitive_surface. D1 (interpreter-primitive-roster consumption): measurement scaffold deleted; primitive_surface_census_derived reads the roster authority. Population-wide identity join closure remains the terminal acceptance bar." @@ -1316,6 +1317,21 @@ data primitive_concept_decl_facts_traversal: PrimitiveTraversalOrderFact = Primi data primitive_concept_decl_facts_live_traversal: PrimitiveTraversalOrderFact = PrimitiveTraversalOrderFact { primitive: primitive_concept_decl_facts_live, order: SourcePreservingOrder } +// THE TWO SYMBOL BRIDGES TRAVERSE NOTHING, and OrderFreeResult is the honest arm rather than the +// convenient one. Both are scalar: symbol_lexeme maps one Symbol to its text and +// symbol_intern_lexeme is its inverse, so there is no collection to walk and the result is a +// function of the input alone -- it cannot depend on an order because no order is consulted. That +// is a different statement from HostUnspecifiedOrder, which would claim a real traversal whose +// order the host does not pin, and asserting it here would fabricate a leak the primitive cannot +// have. Adding these rows is an OBLIGATION of declaring the primitives, not bookkeeping beside it: +// v2.lens.determinism closes its denominator over primitive_declared_definitions, so a primitive +// with no traversal fact makes the closure false. That is how this was found -- nine reach_witness +// rows went red, including determinism_denominator_is_closed_on_declared_primitives, the row whose +// entire job is to notice exactly this. +data primitive_symbol_lexeme_traversal: PrimitiveTraversalOrderFact = PrimitiveTraversalOrderFact { primitive: primitive_symbol_lexeme, order: OrderFreeResult } + +data primitive_symbol_intern_lexeme_traversal: PrimitiveTraversalOrderFact = PrimitiveTraversalOrderFact { primitive: primitive_symbol_intern_lexeme, order: OrderFreeResult } + data primitive_projection_traversal_facts: List = [ primitive_length_traversal, primitive_map_insert_traversal, @@ -1326,6 +1342,8 @@ data primitive_projection_traversal_facts: List = [ primitive_data_decl_type_facts_traversal, primitive_concept_decl_facts_traversal, primitive_concept_decl_facts_live_traversal, + primitive_symbol_lexeme_traversal, + primitive_symbol_intern_lexeme_traversal, ] fn primitive_declared_traversal_facts() -> List { diff --git a/src/v1/stage0/src/namespace_wave_admission.rs b/src/v1/stage0/src/namespace_wave_admission.rs index 4fa2876b39a..fb106ff51bb 100644 --- a/src/v1/stage0/src/namespace_wave_admission.rs +++ b/src/v1/stage0/src/namespace_wave_admission.rs @@ -367,7 +367,66 @@ pub struct TransitionAdmission { /// the shape the paragraph above records for the first 53. Removed by the trigger they were /// authored with. The roster is EMPTY and empty is not permissive: a run carrying a real /// namespace delta still refuses it as UNADJUDICATED until its author adds a row here. -pub const NAMESPACE_TRANSITION_ADMISSIONS: &[TransitionAdmission] = &[]; +/// FOURTH TRANSITION (2026-08-29, gunbc#9665 / issue #9664). `DeclaredCallableIdentity` moved +/// from `v1.compiler.infer_sigs` to `v1.std.core`, so every binding of that spelling inside +/// `v1.compiler.infer_lookup` reports `TargetChanged`. The move is not cosmetic and not +/// avoidable by re-spelling: `v1.std.core`'s own `CallTargetIdentity` now CARRIES a +/// `DeclaredCallableIdentity` on its `RuntimePrimitiveCall` arm -- the declaration a runtime +/// target was projected from, which is what lets Rust emission fall back to the declaration +/// when its registry has no bridge for the primitive instead of inventing `v1_rt::length`. +/// `v1.compiler.infer_sigs` imports `v1.std.core`, so the type could not stay where it was +/// without a cycle, and re-declaring the pair in `v1.std.core` beside the original is the +/// second-representation defect DESIGN §3 forbids -- the type's own note already says so, and +/// that note travelled with the declaration. +/// +/// FOUR ROWS, ONE PER BINDING SITE, and they are enumerated rather than matched by a module +/// pattern because the roster's own rule is that its population is an enumeration and never a +/// predicate. The two `membership` deltas this change also produces +/// (`v1.compiler.emit_rust -> std.decl_ref` and `-> std.primitive_projection`) are +/// `ExplicitlyEvaluatedZeroDelta` and auto-admit, so they are deliberately absent here. +/// +/// DISSOLVE-ON: this PR merging. Once `DeclaredCallableIdentity` is declared in `v1.std.core` +/// on main, the merge base and head both carry it, no run can produce these deltas, and all +/// four report stale -- which refuses every unrelated PR in the repository, exactly the shape +/// the three shrinks above record. Remove them by that trigger, not by reinterpreting it. +pub const NAMESPACE_TRANSITION_ADMISSIONS: &[TransitionAdmission] = &[ + TransitionAdmission { + label: "DeclaredCallableIdentity hoist to v1.std.core 2026-08-29", + subject: AdmissionSubject::Binding { + module: "v1.compiler.infer_lookup", + in_declaration: "borrowed_census_callable_candidate", + spelling: "DeclaredCallableIdentity", + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: "DeclaredCallableIdentity hoist to v1.std.core 2026-08-29", + subject: AdmissionSubject::Binding { + module: "v1.compiler.infer_lookup", + in_declaration: "callable_lookup_over_candidates", + spelling: "DeclaredCallableIdentity", + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: "DeclaredCallableIdentity hoist to v1.std.core 2026-08-29", + subject: AdmissionSubject::Binding { + module: "v1.compiler.infer_lookup", + in_declaration: "func_sig_from_global_bare", + spelling: "DeclaredCallableIdentity", + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: "DeclaredCallableIdentity hoist to v1.std.core 2026-08-29", + subject: AdmissionSubject::Binding { + module: "v1.compiler.infer_lookup", + in_declaration: "resolved_declaration_call_target", + spelling: "DeclaredCallableIdentity", + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, +]; /// The denominators a green must name (DESIGN §5). A run that cannot say what it covered is /// an instrument failure wearing coverage's clothes. From d0de2a4dd3e5707e00484dbd648549ddd402e2e1 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 10:04:22 +0000 Subject: [PATCH 14/30] Class-C fixture was broken, not the repair: the witness pool is smaller than the corpus The row FAILED while the mechanism was green. The probe used the qualified spelling without importing v2.std.collection, which resolves against the real 4261-module corpus but not against compile_dag_rust_emit_check's 2973-module witness pool. Measured both ways: emitted against the corpus the same probe produces crate::v2_std_collection::map_get(m.clone(), "key".to_string()), exactly what the row asserts. The import restores module presence and does not answer the call -- decl_name comes from the authored spelling at the call site regardless of imports -- so the negative assertion still discriminates. Falsifier 2 is what proves that rather than argues it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...emitted_call_target_realization_witness_test.dag | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 5ea0b3fe224..cd91aa1ecd4 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -6,6 +6,17 @@ data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly data emitted_call_target_realization_witness_note: String = "PERMANENT REGRESSION CONTROLS for the three emission defects that stood between the v2 compiler closure and a Rust crate rustc would accept (gunbc#9664 milestones 1 and 2). All three are one family -- emission ASSERTING a realization it had not established -- and each row here is the discriminating RED for one of them, paired with a boundary control that would go red if the repair had over-reached in the opposite direction.\n\nMEASURED POPULATIONS on the emitted closure at main 6447dd4, by `gunbc compile --entry src/v2/compiler/00_compile.dag --target rust` then `cargo check`: 260 coded errors, 254 of them E0425. Class C 102 (98 `v2` + 4 `std`), length 73, class B 65 (member 11, apply 11, is_empty 5, allocate_literal 4, step 3, init 3, and a tail of ones and twos).\n\nWHY THESE ARE NOT A SNAPSHOT. Each class's positive and negative assertion differ only in the fact the repair added, so no single edit satisfies both directions. The C rows would flip if decl_name reverted to the authored spelling; the length rows would flip if the registry membership gate were removed OR if the declaration fallback were extended to seams; the B rows would flip if runtime_bridge went back to a literal. The boundary controls (empty_map, a real bridge method) would flip if any of the three repairs had instead stopped emission reaching v1_rt at all.\n\nDISSOLVE-ON: never. Emission may change target SPELLING, but it may never again name a runtime symbol it has not established exists." +// THE PROBE IMPORTS v2.std.collection AND THEN CALLS IT BY ITS QUALIFIED NAME, which looks +// redundant and is not. compile_dag_rust_emit_check compiles through the witness harness's +// restricted pool (2973 modules against the corpus's 4261), and a qualified spelling alone does not +// put the target module in it -- so without the import this row FAILED while the repair was green, +// which is how it was found. Measured both ways: the same probe emitted against the real corpus +// produces `crate::v2_std_collection::map_get(m.clone(), "key".to_string())` exactly as asserted. +// The import restores module presence; it does not answer the call, because decl_name is taken from +// the authored spelling at the CALL SITE regardless of what is imported -- which is why the +// negative assertion below still discriminates, and why falsifier 2 (restore the dotted spelling) +// must red this row. +// // CLASS C, THE DISCRIMINATING RED. A qualified call carried the whole dotted path as its // declaration name, so emission produced `crate::v2_std_collection::v2.std.collection.map_get(..)` // -- the module prefix correct and the identifier a dotted path Rust reads as field access on an @@ -13,7 +24,7 @@ data emitted_call_target_realization_witness_note: String = "PERMANENT REGRESSIO // row proves the qualified path reaches the DECLARATION and not the bridge. test fn w_qualified_call_emits_only_the_declaration_last_segment() -> Bool { compile_dag_rust_emit_check( - "module test.claim.qualified_call_probe\nimport std.types { Int, String, Map }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.diagnostic { Outcome }\nimport v2.std.optional { Optional }\nfn probe(m: Map) -> Outcome> { v2.std.collection.map_get(m: m, key: \"key\") }\n", + "module test.claim.qualified_call_probe\nimport std.types { Int, String, Map }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.collection { map_get }\nimport v2.std.diagnostic { Outcome }\nimport v2.std.optional { Optional }\nfn probe(m: Map) -> Outcome> { v2.std.collection.map_get(m: m, key: \"key\") }\n", "src/test_claim_qualified_call_probe.rs", ["crate::v2_std_collection::map_get("], ["::v2.std.collection", "v2.std.collection.map_get("] From 51fb9111c3d81a238bf31dc7fd11eee08c253f26 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 10:05:39 +0000 Subject: [PATCH 15/30] is_empty: a conversion is not a repair -- give it the Rust realization it never had Before the class-B change, xs |> is_empty emitted v1_rt::is_empty, a symbol the seed does not define: 5 x E0425. After it, the same 5 sites became typed refusals -- correct in kind, still 5 errors. The class-B repair made the gap visible; it did not close it. is_empty is an algebra template over FreeMonoid whose Rust realization is Vec::is_empty, exactly as count's is Vec::len, so the fix is one row in rust_simple_method_specs beside count. Nothing in 05_emit_rust learns a new name: realization is a target fact and lives in the target's registry. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- dag/extdeps/languages/rust/emit.dag | 3 ++- ...d_call_target_realization_witness_test.dag | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dag/extdeps/languages/rust/emit.dag b/dag/extdeps/languages/rust/emit.dag index bc6be0952ec..906424fb1be 100644 --- a/dag/extdeps/languages/rust/emit.dag +++ b/dag/extdeps/languages/rust/emit.dag @@ -76,7 +76,8 @@ data rust_simple_method_specs: List = [ { method_name: "enumerate", template: "\{recv\}.iter().cloned().enumerate().map(|(i, v)| (i as i64, v)).collect::>()", wraps_result: true }, { method_name: "chars", template: "\{recv\}.chars().map(|c| c as i64).collect::>()", wraps_result: true }, { method_name: "skip", template: "\{recv\}.iter().cloned().skip(\{arg\} as usize).collect::>()", wraps_result: true }, - { method_name: "take", template: "\{recv\}.iter().cloned().take(\{arg\} as usize).collect::>()", wraps_result: true } + { method_name: "take", template: "\{recv\}.iter().cloned().take(\{arg\} as usize).collect::>()", wraps_result: true }, + { method_name: "is_empty", template: "\{recv\}.is_empty()", wraps_result: false } ] fn rust_method_templates() -> Map { diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index cd91aa1ecd4..036c4425a68 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -187,3 +187,22 @@ test fn w_realized_seam_keeps_its_declaration_and_delegates_to_the_bridge() -> B ["has no realization for this target"] ) } + +// is_empty HAD NO RUST REALIZATION AT ALL, and the class-B repair is what made that visible rather +// than what caused it. Before it, `xs |> is_empty` emitted `v1_rt::is_empty(..)` -- a symbol the +// seed does not define -- and appeared in the census as 5 x E0425. After it, the same 5 sites +// became typed refusals: correct in KIND, and still 5 errors. A conversion is not a repair, so this +// row exists to pin the actual realization. +// +// THE ROW IS A TARGET FACT, NOT EMITTER CODE. is_empty is an algebra template over FreeMonoid whose +// Rust realization is Vec::is_empty, exactly as count's is Vec::len -- so it belongs in +// rust_simple_method_specs beside count, and nothing in 05_emit_rust learns a new name. The +// negative assertion is the refusal message, because that is precisely the state this row leaves. +test fn w_is_empty_lowers_to_its_rust_realization_not_a_refusal() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.is_empty_probe\nimport std.types { Int, Bool }\nimport std.occurrence_identity { OccurrenceId }\nimport v2.std.algebra { FreeMonoid, is_empty }\nfn probe(xs: FreeMonoid) -> Bool { xs |> is_empty }\n", + "src/test_claim_is_empty_probe.rs", + [".is_empty()"], + ["v1_rt::is_empty(", "neither a resolved callable receiver field"] + ) +} From a715f1c5edb89e009960fe6ce26efd78ab54c3a2 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 10:14:23 +0000 Subject: [PATCH 16/30] A receiver's own callable field outranks every name-keyed table: class B survived one layer up The requested is_empty negative control found a live hole rather than confirming a safe one. Both rust_method_templates lookups are keyed on the bare method spelling with no receiver check, so a fn-typed record field named is_empty was captured by the target template and emitted as recv.is_empty() instead of (recv.is_empty)(..). The class-B repair fixed the algebra FALLBACK and left the two tables sitting in front of it. The hole is not new and is not specific to is_empty: count, first, join, split, take, skip, last, chars and enumerate have carried it for as long as they have had templates. Adding is_empty made it urgent by putting the spelling most likely to name a predicate field in front of that table. One helper, consulted at the top of both arms before every name-keyed special case, so the two cannot drift. Two controls: the new spelling and a pre-existing one. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...d_call_target_realization_witness_test.dag | 31 +++++++++++++++++ src/v1/05_emit_rust.dag | 34 +++++++++++++++++-- 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 036c4425a68..2e620669f3f 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -206,3 +206,34 @@ test fn w_is_empty_lowers_to_its_rust_realization_not_a_refusal() -> Bool { ["v1_rt::is_empty(", "neither a resolved callable receiver field"] ) } + +// THE NEGATIVE IDENTITY CONTROL FOR THE is_empty ROW, and it caught a live hole rather than +// confirming a safe one. Adding is_empty to rust_simple_method_specs put a new spelling in front of +// the two rust_method_templates lookups -- and those lookups are keyed on the bare name with no +// receiver check, so a fn-typed record field named is_empty was captured by the target template and +// emitted as `recv.is_empty()` instead of `(recv.is_empty)(..)`. That is class B surviving one +// layer up: the class-B repair fixed the algebra FALLBACK and left the tables in front of it. +// +// The same hole existed for count, first, join, split, take, skip, last, chars and enumerate before +// is_empty was ever added; this row is the one that made it executable. +test fn w_callable_field_named_is_empty_is_not_captured_by_the_target_template() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.is_empty_field_probe\nimport std.types { Bool, Int }\ntype Probe { is_empty: fn(Int) -> Bool }\nfn probe(p: Probe, n: Int) -> Bool { p.is_empty(n) }\n", + "src/test_claim_is_empty_field_probe.rs", + [".is_empty)("], + ["p.is_empty()"] + ) +} + +// THE SAME CONTROL FOR A SPELLING THAT WAS ALREADY IN THE TABLE. count has had a template since +// before this change, so if the hole were specific to is_empty this row would be green on main and +// green here. It is not: it is the pre-existing instance of the class, and it is enrolled so the +// repair is measured against the whole table rather than the row that exposed it. +test fn w_callable_field_named_count_is_not_captured_by_the_target_template() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.count_field_probe\nimport std.types { Int }\ntype Counter { count: fn(Int) -> Int }\nfn probe(c: Counter, n: Int) -> Int { c.count(n) }\n", + "src/test_claim_count_field_probe.rs", + [".count)("], + ["c.count()"] + ) +} diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index e866e2f3baf..18307efce60 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -10402,7 +10402,10 @@ fn emit_typed_method_call(method_call_node: Node, receiver: Node, method: String let method_name = if method_name_raw == "length" { if is_string_typed_expr(e: receiver, source_indices: scope.type_env.source_indices) { "string_length" } else { "count" } } else { method_name_raw } - if method_name == "fold" { + let algebra_field_call = rust_callable_field_method_call(method_name: method_name, receiver: receiver, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) + if algebra_field_call != none { + match algebra_field_call { Present { value: field_call } => field_call Absent => "" } + } else if method_name == "fold" { emit_rust_fold_method_call(method_call_node: method_call_node, fold_accumulator_type: fold_accumulator_type, result_type: result_type, receiver: receiver, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } else if method_name == "sort_by" { emit_rust_sort_by_method_call(receiver: receiver, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) @@ -10448,7 +10451,12 @@ fn emit_typed_method_call(method_call_node: Node, receiver: Node, method: String } } PlainMethodSemantics => - if method == "get" && is_collection_typed_expr(texpr: receiver, source_indices: scope.type_env.source_indices) { + if rust_callable_field_method_call(method_name: method, receiver: receiver, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) != none { + match rust_callable_field_method_call(method_name: method, receiver: receiver, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) { + Present { value: field_call } => field_call + Absent => "" + } + } else if method == "get" && is_collection_typed_expr(texpr: receiver, source_indices: scope.type_env.source_indices) { emit_rust_get_method_call(receiver: receiver, args: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) } else { let recv_str = emit_typed_expr(texpr: receiver, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024) @@ -10987,6 +10995,28 @@ fn rust_record_field_needs_fn_rc(scope: InferScope, struct_name: String, field_n // The rt_functions() name guard that stood here is gone: the ONE caller now passes // `runtime_bridge` from the resolution that decided it, so this answers only the question it is // named for -- does the receiver have a callable field by this name. +// THE RECEIVER'S OWN CALLABLE FIELD OUTRANKS EVERY NAME-KEYED TABLE, and this is the same class as +// class B one layer up. That repair stopped the algebra FALLBACK from asserting a v1_rt bridge for +// a fn-typed record field, but left the two rust_method_templates lookups in front of it keyed on +// the bare spelling -- so a field named count, first, join, split, take, skip, last, chars, +// enumerate or is_empty was still captured by a target template and emitted as `recv.count()` +// rather than `(recv.count)(..)`. Adding the is_empty row to rust_simple_method_specs is what made +// this urgent: it put a brand-new spelling in front of that table, and the spelling most likely to +// name a predicate field. +// +// A receiver that genuinely has a fn-typed field of this name is answering with its OWN structure, +// which no global roster can outrank -- so the check goes before the tables rather than after them, +// and one helper serves both arms so the two cannot drift. +fn rust_callable_field_method_call(method_name: String, receiver: Node, args: List, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String? { + if rust_receiver_has_callable_method_field(receiver: receiver, method_name: method_name, scope: scope) { + let recv_str = emit_typed_expr_base(texpr: receiver, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) + let arg_strs = args |> map(a => emit_cloned_arg(texpr: arg_value(n: a), registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info)) + Present { value: concat("(", recv_str, ".", emit_ident(name: method_name, target: Rust), ")(", arg_strs |> join(separator: ", "), ")") } + } else { + none + } +} + fn rust_receiver_has_callable_method_field(receiver: Node, method_name: String, scope: InferScope) -> Bool { let receiver_type = resolved_type(n: receiver) let receiver_type_name = authored_name_at(source_indices: scope.type_env.source_indices, node: receiver_type) From 54a1bbe12a20fdc6aed10565894b98e0069b8419 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 10:32:23 +0000 Subject: [PATCH 17/30] Two more wave admissions: the declaring module rebinds too v1.compiler.infer_sigs used to DECLARE DeclaredCallableIdentity, so its own two construction sites resolved locally and produced no delta. Now that the declaration lives in v1.std.core and infer_sigs imports it, those sites rebind exactly like the consumers in infer_lookup. An enumeration error on my part, not a second transition: same subject, same trigger, same dissolve. Floor is now green on this branch (passed=2754 failed=0) -- the OrderFreeResult traversal facts closed all nine determinism rows. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- src/v1/stage0/src/namespace_wave_admission.rs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/v1/stage0/src/namespace_wave_admission.rs b/src/v1/stage0/src/namespace_wave_admission.rs index fb106ff51bb..cd17b796a93 100644 --- a/src/v1/stage0/src/namespace_wave_admission.rs +++ b/src/v1/stage0/src/namespace_wave_admission.rs @@ -426,6 +426,30 @@ pub const NAMESPACE_TRANSITION_ADMISSIONS: &[TransitionAdmission] = &[ }, disposition: NamespaceDeltaDisposition::TargetChanged, }, + // THE DECLARING MODULE REBINDS TOO, which the first four rows missed. `v1.compiler.infer_sigs` + // used to DECLARE `DeclaredCallableIdentity`, so its own two construction sites resolved + // locally and produced no delta; now that the declaration lives in `v1.std.core` and this + // module imports it, those sites rebind exactly like the consumers in `infer_lookup`. Missing + // them was an enumeration error on my part, not a second transition: same subject, same + // trigger, same dissolve. + TransitionAdmission { + label: "DeclaredCallableIdentity hoist to v1.std.core 2026-08-29", + subject: AdmissionSubject::Binding { + module: "v1.compiler.infer_sigs", + in_declaration: "lookup_resolved_sig", + spelling: "DeclaredCallableIdentity", + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, + TransitionAdmission { + label: "DeclaredCallableIdentity hoist to v1.std.core 2026-08-29", + subject: AdmissionSubject::Binding { + module: "v1.compiler.infer_sigs", + in_declaration: "parent_closure_callable_candidates", + spelling: "DeclaredCallableIdentity", + }, + disposition: NamespaceDeltaDisposition::TargetChanged, + }, ]; /// The denominators a green must name (DESIGN §5). A run that cannot say what it covered is From 952ffa6ef49fdd11774a788d1d9769b59dc41a5e Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 11:55:25 +0000 Subject: [PATCH 18/30] The callable-field tier was consuming the algebra profile's identity domain, not the receiver's: 202 refusals on the first compile of the converged seed rust_receiver_has_callable_method_field asked rust_record_field_needs_fn_rc, which sweeps rust_struct_field_lookup_candidates -- and that list deliberately widens a receiver's name to its container template algebra. An algebra declares its operations as arrow-typed members, so under that widening every Map receiver "has a callable field" named map_keys, map_values, lookup or get, and the tier captured the very bridge calls it sits in front of. Measured at the first compile of the round-3 converged mirror: 202 rustc refusals, one class -- 164 E0609 (no field `map_keys` on Rc>> and friends), 48 E0282, 4 E0615 on `get`. It is the same defect the tier was built to close, one level up: a name-keyed lookup consuming an identity domain that is not its own. The predicate now consults only the receiver's own declared record. w_map_receiver_operation_is_not_read_as_a_callable_field is the discriminating red: restore the candidate sweep and its must_not_contain clause fires. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...ed_call_target_realization_witness_test.dag | 18 ++++++++++++++++++ src/v1/05_emit_rust.dag | 16 +++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index 2e620669f3f..c119cfcdccc 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -237,3 +237,21 @@ test fn w_callable_field_named_count_is_not_captured_by_the_target_template() -> ["c.count()"] ) } + +// THE ALGEBRA-PROFILE CONTROL FOR THE CALLABLE-FIELD TIER, and the direct regression control for +// the 202-refusal class it caused. The tier asked rust_record_field_needs_fn_rc, whose candidate +// list widens a receiver's name to its CONTAINER TEMPLATE ALGEBRA -- and an algebra declares its +// operations as arrow-typed members, so a Map receiver read as having a callable field named +// map_keys, and the tier emitted `(m.map_keys)(..)` for a call rustc then refused with E0609 no +// field `map_keys` on Rc>. The receiver here is a genuine Map, so the tier must +// decline it and the ordinary bridge lowering must survive. This is the discriminating red for +// narrowing the predicate to the receiver's OWN declared record: restore the candidate sweep and +// the must_not_contain clause fires. +test fn w_map_receiver_operation_is_not_read_as_a_callable_field() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.map_receiver_probe\nimport std.types { Int, String }\nfn probe(m: Map) -> List { map_keys(m) }\n", + "src/test_claim_map_receiver_probe.rs", + ["map_keys"], + [".map_keys)("] + ) +} diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 7ad4a7aa490..dc7dfff8dd1 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -11036,10 +11036,24 @@ fn rust_callable_field_method_call(method_name: String, receiver: Node, args: Li } } +// THE RECEIVER'S OWN DECLARED RECORD, NEVER ITS ALGEBRA PROFILE. This asked +// rust_record_field_needs_fn_rc, which sweeps rust_struct_field_lookup_candidates -- and that +// candidate list deliberately widens a receiver's name to its container template algebra so +// FIELD-TYPE questions can be answered through the profile. An algebra declares its OPERATIONS as +// arrow-typed members, so under that widening every Map receiver "has a callable field" named +// map_keys, map_values, lookup or get, and the callable-field tier captured the very bridge calls +// it sits in front of: 202 rustc refusals on the regenerated seed (E0609 no field `map_keys` on +// Rc>, E0615 on `get`), one class, measured at the first compile of the converged +// mirror. That is the SAME defect this tier was built to close, one level up -- a name-keyed +// lookup consuming an identity domain that is not its own -- so the fix is to consume only the +// domain this question is about: a field declared on the receiver's own record. fn rust_receiver_has_callable_method_field(receiver: Node, method_name: String, scope: InferScope) -> Bool { let receiver_type = resolved_type(n: receiver) let receiver_type_name = authored_name_at(source_indices: scope.type_env.source_indices, node: receiver_type) - rust_record_field_needs_fn_rc(scope: scope, struct_name: receiver_type_name, field_name: method_name) + match rust_struct_field_type_node(scope: scope, struct_name: receiver_type_name, field_name: method_name) { + Present { value: field_type } => field_type.connective == Arrow + Absent => false + } } fn rust_struct_field_type_node_variant_aware(scope: InferScope, emit_info: EmitGraphInfo, struct_name: String, field_name: String) -> Node? { From 443f3de208b886d50623b0235181f7f6fb9c479a Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 13:56:38 +0000 Subject: [PATCH 19/30] Regenerate the stage0 mirror at the merge-equivalent tree: byte fixed point at round 3, six paths, each explained by an authority change Convergence transaction on srv1 (/tmp/xl0c.sh -> /tmp/xl0g.log), on 952ffa6 = main b726547 merged with the branch. Criterion is BYTE equality (sha256 over the whole candidate tree vs the whole installed tree), never first_generation_equal and never the changed-path list; the full workspace is rebuilt inside every round so a non-compiling mirror stops the line. round 1 cand e212fe74 inst 6f55cf3e installed, compiles round 2 cand 932b0543 inst e212fe74 drift = v1_rt.rs only (the two-hop: v1_rt.rs is rendered by the previously compiled rt_hash_ops) round 3 cand 932b0543 inst 932b0543 BYTE FIXED POINT -- produced by a compiler rebuilt from the round-2 installed tree Changed paths and their authority: extdeps_languages_rust_emit.rs <- rt_function_registry / rust_simple_method_specs rows std_primitive_projection.rs <- symbol_lexeme / symbol_intern_lexeme roster rows v1_compiler_emit_rust.rs <- 05_emit_rust.dag (seam wall, callable-field tier, class B/C) v1_compiler_infer.rs <- 04_infer.dag projected_from on RuntimePrimitiveCall v1_compiler_runtime_rust.rs <- runtime_rust.dag symbol bridges v1_rt.rs <- same, one hop later On these bytes: function_value_named_application_controls_witness PASSES (the d805243 / 952ffa6 rust-unit-tests red was the merge-driver-refused stale v1_compiler_infer.rs, not a semantic regression); emit 175 files; cargo check 15 errors: 9 E0425 (filesystem 2, V 2, K 2, Determinism 2, T 1), 2 E0728, 2 E0107, 1 E0391, 1 UNRESOLVED_CompilerError. No hand edit to any generated file. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- .../stage0/src/extdeps_languages_rust_emit.rs | 4 +- src/v1/stage0/src/std_primitive_projection.rs | 39 ++ src/v1/stage0/src/v1_compiler_emit_rust.rs | 581 +++++++++++------- src/v1/stage0/src/v1_compiler_infer.rs | 30 +- src/v1/stage0/src/v1_compiler_runtime_rust.rs | 2 +- src/v1/stage0/src/v1_rt.rs | 14 + 6 files changed, 439 insertions(+), 231 deletions(-) diff --git a/src/v1/stage0/src/extdeps_languages_rust_emit.rs b/src/v1/stage0/src/extdeps_languages_rust_emit.rs index 455431df768..fd50682ac44 100644 --- a/src/v1/stage0/src/extdeps_languages_rust_emit.rs +++ b/src/v1/stage0/src/extdeps_languages_rust_emit.rs @@ -89,7 +89,7 @@ pub fn rust_container_templates() -> Rc> { pub fn rust_simple_method_specs() -> Rc>> { thread_local! { static CACHED: Rc>> = { - serde_json::from_value(serde_json::json!([{"method_name": "count", "template": "({recv}.len() as i64)", "wraps_result": false}, {"method_name": "join", "template": "{recv}.join(&{arg})", "wraps_result": false}, {"method_name": "split", "template": "{recv}.split(&{arg}).map(|s| s.to_string()).collect::>()", "wraps_result": true}, {"method_name": "last", "template": "{recv}.last().cloned()", "wraps_result": false}, {"method_name": "first", "template": "{recv}.first().cloned()", "wraps_result": false}, {"method_name": "enumerate", "template": "{recv}.iter().cloned().enumerate().map(|(i, v)| (i as i64, v)).collect::>()", "wraps_result": true}, {"method_name": "chars", "template": "{recv}.chars().map(|c| c as i64).collect::>()", "wraps_result": true}, {"method_name": "skip", "template": "{recv}.iter().cloned().skip({arg} as usize).collect::>()", "wraps_result": true}, {"method_name": "take", "template": "{recv}.iter().cloned().take({arg} as usize).collect::>()", "wraps_result": true}])) + serde_json::from_value(serde_json::json!([{"method_name": "count", "template": "({recv}.len() as i64)", "wraps_result": false}, {"method_name": "join", "template": "{recv}.join(&{arg})", "wraps_result": false}, {"method_name": "split", "template": "{recv}.split(&{arg}).map(|s| s.to_string()).collect::>()", "wraps_result": true}, {"method_name": "last", "template": "{recv}.last().cloned()", "wraps_result": false}, {"method_name": "first", "template": "{recv}.first().cloned()", "wraps_result": false}, {"method_name": "enumerate", "template": "{recv}.iter().cloned().enumerate().map(|(i, v)| (i as i64, v)).collect::>()", "wraps_result": true}, {"method_name": "chars", "template": "{recv}.chars().map(|c| c as i64).collect::>()", "wraps_result": true}, {"method_name": "skip", "template": "{recv}.iter().cloned().skip({arg} as usize).collect::>()", "wraps_result": true}, {"method_name": "take", "template": "{recv}.iter().cloned().take({arg} as usize).collect::>()", "wraps_result": true}, {"method_name": "is_empty", "template": "{recv}.is_empty()", "wraps_result": false}])) .expect("valid data definition") }; } @@ -525,7 +525,7 @@ pub struct RuntimeFunction { pub fn rt_function_registry() -> Rc>> { thread_local! { static CACHED: Rc>> = { - serde_json::from_value(serde_json::json!([{"name": "concat", "bridge_name": "concat", "passes_by_ref": false, "wraps_result": false}, {"name": "char_at", "bridge_name": "char_at", "passes_by_ref": true, "wraps_result": false}, {"name": "string_length", "bridge_name": "string_length", "passes_by_ref": true, "wraps_result": false}, {"name": "substring", "bridge_name": "substring", "passes_by_ref": true, "wraps_result": false}, {"name": "string_contains", "bridge_name": "string_contains", "passes_by_ref": true, "wraps_result": false}, {"name": "scan_while", "bridge_name": "scan_while", "passes_by_ref": true, "wraps_result": false}, {"name": "skip_horizontal_ws", "bridge_name": "skip_horizontal_ws", "passes_by_ref": true, "wraps_result": false}, {"name": "scan_to_eol", "bridge_name": "scan_to_eol", "passes_by_ref": true, "wraps_result": false}, {"name": "scan_string_end", "bridge_name": "scan_string_end", "passes_by_ref": true, "wraps_result": false}, {"name": "code_point", "bridge_name": "code_point", "passes_by_ref": false, "wraps_result": false}, {"name": "from_code_point", "bridge_name": "from_code_point", "passes_by_ref": false, "wraps_result": false}, {"name": "lookup", "bridge_name": "lookup", "passes_by_ref": true, "wraps_result": false}, {"name": "index_by", "bridge_name": "rc_index_by", "passes_by_ref": false, "wraps_result": false}, {"name": "empty_map", "bridge_name": "rc_empty_map", "passes_by_ref": false, "wraps_result": false}, {"name": "empty_set", "bridge_name": "rc_empty_set", "passes_by_ref": false, "wraps_result": false}, {"name": "set_insert", "bridge_name": "rc_set_insert", "passes_by_ref": false, "wraps_result": false}, {"name": "set_union", "bridge_name": "rc_set_union", "passes_by_ref": false, "wraps_result": false}, {"name": "set_contains", "bridge_name": "set_contains", "passes_by_ref": true, "wraps_result": false}, {"name": "map_insert", "bridge_name": "rc_map_insert", "passes_by_ref": false, "wraps_result": false}, {"name": "map_merge", "bridge_name": "rc_map_merge", "passes_by_ref": false, "wraps_result": false}, {"name": "list_concat", "bridge_name": "rc_list_concat", "passes_by_ref": false, "wraps_result": false}, {"name": "str_eq", "bridge_name": "str_eq", "passes_by_ref": false, "wraps_result": false}, {"name": "filesystem_read", "bridge_name": "filesystem_read", "passes_by_ref": false, "wraps_result": false}, {"name": "list_push", "bridge_name": "rc_list_push", "passes_by_ref": false, "wraps_result": false}, {"name": "map_get", "bridge_name": "map_get", "passes_by_ref": true, "wraps_result": false}, {"name": "map_keys", "bridge_name": "map_keys", "passes_by_ref": true, "wraps_result": true}, {"name": "sorted_map_keys", "bridge_name": "sorted_map_keys", "passes_by_ref": true, "wraps_result": true}, {"name": "map_values", "bridge_name": "map_values", "passes_by_ref": true, "wraps_result": true}, {"name": "parse_int", "bridge_name": "parse_int", "passes_by_ref": false, "wraps_result": false}, {"name": "map_contains_key", "bridge_name": "map_contains_key", "passes_by_ref": true, "wraps_result": false}, {"name": "map_has", "bridge_name": "map_has", "passes_by_ref": true, "wraps_result": false}, {"name": "map_is_empty", "bridge_name": "map_is_empty", "passes_by_ref": true, "wraps_result": false}, {"name": "reverse", "bridge_name": "reverse", "passes_by_ref": false, "wraps_result": false}, {"name": "replace", "bridge_name": "replace", "passes_by_ref": false, "wraps_result": false}, {"name": "chars_to_string", "bridge_name": "chars_to_string", "passes_by_ref": true, "wraps_result": false}, {"name": "record_source_chars_index_lookup", "bridge_name": "record_source_chars_index_lookup", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_is_enabled", "bridge_name": "resolution_silent_pick_is_enabled", "passes_by_ref": false, "wraps_result": false}, {"name": "name_resolution_policy_is_namespace_only", "bridge_name": "name_resolution_policy_is_namespace_only", "passes_by_ref": false, "wraps_result": false}, {"name": "type_ref_hit_ne_bind_measure_active", "bridge_name": "type_ref_hit_ne_bind_measure_active", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_record_global_bare_lcp_pick", "bridge_name": "resolution_silent_pick_record_global_bare_lcp_pick", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_record_global_bare_lcp_tie", "bridge_name": "resolution_silent_pick_record_global_bare_lcp_tie", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_record_fn_parent_first_hit", "bridge_name": "resolution_silent_pick_record_fn_parent_first_hit", "passes_by_ref": false, "wraps_result": false}, {"name": "append", "bridge_name": "append", "passes_by_ref": false, "wraps_result": true}, {"name": "contains", "bridge_name": "contains", "passes_by_ref": false, "wraps_result": false}, {"name": "starts_with", "bridge_name": "starts_with", "passes_by_ref": false, "wraps_result": false}, {"name": "ends_with", "bridge_name": "ends_with", "passes_by_ref": false, "wraps_result": false}, {"name": "trim", "bridge_name": "trim", "passes_by_ref": false, "wraps_result": false}, {"name": "count", "bridge_name": "count", "passes_by_ref": false, "wraps_result": false}, {"name": "clamp", "bridge_name": "clamp", "passes_by_ref": false, "wraps_result": false}, {"name": "atom_identity_hash", "bridge_name": "atom_identity_hash", "passes_by_ref": false, "wraps_result": false}, {"name": "hash_combine", "bridge_name": "hash_combine", "passes_by_ref": false, "wraps_result": false}, {"name": "trace_mark", "bridge_name": "trace_mark", "passes_by_ref": false, "wraps_result": false}, {"name": "rc_ptr_eq", "bridge_name": "rc_ptr_eq", "passes_by_ref": false, "wraps_result": false}, {"name": "rc_vec_ptr_eq", "bridge_name": "rc_vec_ptr_eq", "passes_by_ref": false, "wraps_result": false}, {"name": "is_xid_start", "bridge_name": "is_xid_start", "passes_by_ref": false, "wraps_result": false}, {"name": "is_xid_continue", "bridge_name": "is_xid_continue", "passes_by_ref": false, "wraps_result": false}, {"name": "is_emoji_ident", "bridge_name": "is_emoji_ident", "passes_by_ref": false, "wraps_result": false}])) + serde_json::from_value(serde_json::json!([{"name": "concat", "bridge_name": "concat", "passes_by_ref": false, "wraps_result": false}, {"name": "char_at", "bridge_name": "char_at", "passes_by_ref": true, "wraps_result": false}, {"name": "string_length", "bridge_name": "string_length", "passes_by_ref": true, "wraps_result": false}, {"name": "substring", "bridge_name": "substring", "passes_by_ref": true, "wraps_result": false}, {"name": "string_contains", "bridge_name": "string_contains", "passes_by_ref": true, "wraps_result": false}, {"name": "scan_while", "bridge_name": "scan_while", "passes_by_ref": true, "wraps_result": false}, {"name": "skip_horizontal_ws", "bridge_name": "skip_horizontal_ws", "passes_by_ref": true, "wraps_result": false}, {"name": "scan_to_eol", "bridge_name": "scan_to_eol", "passes_by_ref": true, "wraps_result": false}, {"name": "scan_string_end", "bridge_name": "scan_string_end", "passes_by_ref": true, "wraps_result": false}, {"name": "code_point", "bridge_name": "code_point", "passes_by_ref": false, "wraps_result": false}, {"name": "from_code_point", "bridge_name": "from_code_point", "passes_by_ref": false, "wraps_result": false}, {"name": "lookup", "bridge_name": "lookup", "passes_by_ref": true, "wraps_result": false}, {"name": "index_by", "bridge_name": "rc_index_by", "passes_by_ref": false, "wraps_result": false}, {"name": "empty_map", "bridge_name": "rc_empty_map", "passes_by_ref": false, "wraps_result": false}, {"name": "empty_set", "bridge_name": "rc_empty_set", "passes_by_ref": false, "wraps_result": false}, {"name": "set_insert", "bridge_name": "rc_set_insert", "passes_by_ref": false, "wraps_result": false}, {"name": "set_union", "bridge_name": "rc_set_union", "passes_by_ref": false, "wraps_result": false}, {"name": "set_contains", "bridge_name": "set_contains", "passes_by_ref": true, "wraps_result": false}, {"name": "map_insert", "bridge_name": "rc_map_insert", "passes_by_ref": false, "wraps_result": false}, {"name": "map_merge", "bridge_name": "rc_map_merge", "passes_by_ref": false, "wraps_result": false}, {"name": "list_concat", "bridge_name": "rc_list_concat", "passes_by_ref": false, "wraps_result": false}, {"name": "str_eq", "bridge_name": "str_eq", "passes_by_ref": false, "wraps_result": false}, {"name": "filesystem_read", "bridge_name": "filesystem_read", "passes_by_ref": false, "wraps_result": false}, {"name": "list_push", "bridge_name": "rc_list_push", "passes_by_ref": false, "wraps_result": false}, {"name": "map_get", "bridge_name": "map_get", "passes_by_ref": true, "wraps_result": false}, {"name": "map_keys", "bridge_name": "map_keys", "passes_by_ref": true, "wraps_result": true}, {"name": "sorted_map_keys", "bridge_name": "sorted_map_keys", "passes_by_ref": true, "wraps_result": true}, {"name": "map_values", "bridge_name": "map_values", "passes_by_ref": true, "wraps_result": true}, {"name": "parse_int", "bridge_name": "parse_int", "passes_by_ref": false, "wraps_result": false}, {"name": "map_contains_key", "bridge_name": "map_contains_key", "passes_by_ref": true, "wraps_result": false}, {"name": "map_has", "bridge_name": "map_has", "passes_by_ref": true, "wraps_result": false}, {"name": "map_is_empty", "bridge_name": "map_is_empty", "passes_by_ref": true, "wraps_result": false}, {"name": "reverse", "bridge_name": "reverse", "passes_by_ref": false, "wraps_result": false}, {"name": "replace", "bridge_name": "replace", "passes_by_ref": false, "wraps_result": false}, {"name": "chars_to_string", "bridge_name": "chars_to_string", "passes_by_ref": true, "wraps_result": false}, {"name": "record_source_chars_index_lookup", "bridge_name": "record_source_chars_index_lookup", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_is_enabled", "bridge_name": "resolution_silent_pick_is_enabled", "passes_by_ref": false, "wraps_result": false}, {"name": "name_resolution_policy_is_namespace_only", "bridge_name": "name_resolution_policy_is_namespace_only", "passes_by_ref": false, "wraps_result": false}, {"name": "type_ref_hit_ne_bind_measure_active", "bridge_name": "type_ref_hit_ne_bind_measure_active", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_record_global_bare_lcp_pick", "bridge_name": "resolution_silent_pick_record_global_bare_lcp_pick", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_record_global_bare_lcp_tie", "bridge_name": "resolution_silent_pick_record_global_bare_lcp_tie", "passes_by_ref": false, "wraps_result": false}, {"name": "resolution_silent_pick_record_fn_parent_first_hit", "bridge_name": "resolution_silent_pick_record_fn_parent_first_hit", "passes_by_ref": false, "wraps_result": false}, {"name": "append", "bridge_name": "append", "passes_by_ref": false, "wraps_result": true}, {"name": "contains", "bridge_name": "contains", "passes_by_ref": false, "wraps_result": false}, {"name": "starts_with", "bridge_name": "starts_with", "passes_by_ref": false, "wraps_result": false}, {"name": "ends_with", "bridge_name": "ends_with", "passes_by_ref": false, "wraps_result": false}, {"name": "trim", "bridge_name": "trim", "passes_by_ref": false, "wraps_result": false}, {"name": "count", "bridge_name": "count", "passes_by_ref": false, "wraps_result": false}, {"name": "clamp", "bridge_name": "clamp", "passes_by_ref": false, "wraps_result": false}, {"name": "atom_identity_hash", "bridge_name": "atom_identity_hash", "passes_by_ref": false, "wraps_result": false}, {"name": "hash_combine", "bridge_name": "hash_combine", "passes_by_ref": false, "wraps_result": false}, {"name": "trace_mark", "bridge_name": "trace_mark", "passes_by_ref": false, "wraps_result": false}, {"name": "rc_ptr_eq", "bridge_name": "rc_ptr_eq", "passes_by_ref": false, "wraps_result": false}, {"name": "rc_vec_ptr_eq", "bridge_name": "rc_vec_ptr_eq", "passes_by_ref": false, "wraps_result": false}, {"name": "is_xid_start", "bridge_name": "is_xid_start", "passes_by_ref": false, "wraps_result": false}, {"name": "is_xid_continue", "bridge_name": "is_xid_continue", "passes_by_ref": false, "wraps_result": false}, {"name": "is_emoji_ident", "bridge_name": "is_emoji_ident", "passes_by_ref": false, "wraps_result": false}, {"name": "symbol_lexeme", "bridge_name": "symbol_lexeme", "passes_by_ref": false, "wraps_result": false}, {"name": "symbol_intern_lexeme", "bridge_name": "symbol_intern_lexeme", "passes_by_ref": false, "wraps_result": false}])) .expect("valid data definition") }; } diff --git a/src/v1/stage0/src/std_primitive_projection.rs b/src/v1/stage0/src/std_primitive_projection.rs index dbc97abfbea..ecf7cc5961e 100644 --- a/src/v1/stage0/src/std_primitive_projection.rs +++ b/src/v1/stage0/src/std_primitive_projection.rs @@ -191,6 +191,33 @@ pub fn primitive_concept_decl_facts_live() -> Rc { CACHED.with(|c: &Rc| c.clone()) } +pub fn primitive_symbol_lexeme() -> Rc { + thread_local! { + static CACHED: Rc = { + primitive_identity_slug("symbol_lexeme".to_string()) + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn primitive_symbol_intern_lexeme() -> Rc { + thread_local! { + static CACHED: Rc = { + primitive_identity_slug("symbol_intern_lexeme".to_string()) + }; + } + CACHED.with(|c: &Rc| c.clone()) +} + +pub fn symbol_lexeme_seam_disposition_note() -> String { + thread_local! { + static CACHED: String = { + "THE TWO SYMBOL BRIDGES WERE HOST SEAMS THAT NOTHING SAID WERE HOST SEAMS, and the cost of that silence is why they are rostered here rather than left alone. v2.std.compilers.lexing symbol_lexeme and symbol_intern_lexeme have self-call bodies -- the HostRealizedSeam shape exactly, correct by construction because reaching one recurses to the evaluation-budget refusal -- and the interpreter has carried real arms for both since they were written (gunbc.v1_interpreter_primitive_surface v4_bridge.symbol_lexeme, v4_bridge.symbol_intern_lexeme). But with no roster row the RESOLVER saw an ordinary declaration, so Rust emission emitted the declaration, and `pub fn symbol_lexeme(sym: String) -> String { symbol_lexeme(sym) }` COMPILES. The emitted v2 compiler closure therefore carried two functions that type-check, pass every gate we own, and diverge from the interpreter by not terminating -- the DESIGN section 5 fabricated-plausible-output failure in its quietest form, since unlike the sibling seams (decl_facts and friends, which at least refuse loudly as unresolved v1_rt symbols) nothing anywhere reports this one.\n\nWHAT MAKES THE RUST REALIZATION HONEST RATHER THAN A SHIM: extdeps.languages.rust.types already declares Symbol's target type as String, so on that target the interning table is the identity and both bridges ARE identity functions. That is a realization of the declared row, not a second opinion about it; a target where Symbol is NOT String would need a different realization and the registry is where it would say so. The interpreter's arms and the Rust registry rows now answer for the same two primitives, which is the agreement that was missing.\n\nTHE RESIDUE IS NAMED, NOT CLOSED: a self-call body is a DECIDABLE structural marker of a host seam, so the compiler could refuse an unrealized one instead of emitting it. It does not yet, and until it does this roster is the only thing standing between a new v4_bridge declaration and another silently nonterminating emission. That check is this class's next-rung trigger.".to_string() + }; + } + CACHED.with(|c: &String| c.clone()) +} + pub fn primitive_projection_roster_note() -> String { thread_local! { static CACHED: String = { @@ -251,6 +278,18 @@ pub fn primitive_projection_roster() -> Rc>> { "empty_map_primitive_delegate".to_string(), Rc::new(ProjectionFidelity::HostRealizedSeam), ), + primitive_projection_row( + primitive_symbol_lexeme(), + "v2.std.compilers.lexing".to_string(), + "symbol_lexeme".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), + primitive_projection_row( + primitive_symbol_intern_lexeme(), + "v2.std.compilers.lexing".to_string(), + "symbol_intern_lexeme".to_string(), + Rc::new(ProjectionFidelity::HostRealizedSeam), + ), primitive_projection_row( primitive_length(), "v2.std.algebra".to_string(), diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 8fb74c5ea3f..9dcd2f15425 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -37,12 +37,17 @@ pub use crate::gunbc_stage0_emitted_population_manifest::{ pub use crate::std_algebra::trim; pub use crate::std_coercion::TypeCheckpoint; pub use crate::std_content_hash::Fnv1a64Structural; +pub use crate::std_decl_ref::decl_ref; +pub use crate::std_decl_ref::DeclarationRef; use crate::std_induction::SubValueRelation::SubValueUnknown; pub use crate::std_induction::{InductiveField, SubValueRelation}; pub use crate::std_measure::millisecond_count; pub use crate::std_nat::Nat; pub use crate::std_occurrence_identity::NodeOccurrenceIdentity; use crate::std_occurrence_identity::NodeOccurrenceIdentity::OccurrenceSynthetic; +pub use crate::std_primitive_projection::{ + primitive_identity_runtime_name, primitive_projection_row_for_declaration, +}; use crate::std_serialization::VariantEncoding::*; use crate::std_serialization::VariantNaming::*; pub use crate::std_serialization::{CoproductWireContract, VariantEncoding, VariantNaming}; @@ -6579,17 +6584,16 @@ pub fn collect_anonymous_record_lit_heads( } pub fn collect_items_field_import_surface_names( - items: Rc>>, + surface_names: Rc>, emit_info: Rc, - source_indices: Rc>>, ) -> Rc> { { let type_summaries = emit_info.type_summaries.clone(); let variant_to_enum = emit_info.variant_to_enum.clone(); crate::v1_compiler_emit_core_support::unique_strings(Rc::new({ let mut __result = Vec::new(); - for item in items.iter().cloned() { - __result.extend((*Rc::new({ let mut __result = Vec::new(); for type_name in collect_item_emit_surface_names(item.clone(), source_indices.clone(), emit_info.clone()).iter().cloned() { __result.extend((*{ + for type_name in surface_names.iter().cloned() { + __result.extend((*{ let summary_lookup = match v1_rt::map_get(&type_summaries, type_name.clone()) { Some(summary) => Some(summary.clone()), None => match v1_rt::map_get(&variant_to_enum, type_name.clone()) { @@ -6611,7 +6615,7 @@ match summary_lookup.clone() { }) { __result.push(field_type); } } __result }), None => Rc::new(vec![]), } -}).iter().cloned()); } __result })).iter().cloned()); +}).iter().cloned()); } __result })) @@ -8177,7 +8181,7 @@ pub fn reference_derived_use_line_plan( } __result })); - let type_surface_names = crate::v1_compiler_emit_core_support::unique_strings(Rc::new({ + let item_emit_surface_names = Rc::new({ let mut __result = Vec::new(); for item in items.iter().cloned() { __result.extend( @@ -8191,11 +8195,12 @@ pub fn reference_derived_use_line_plan( ); } __result - })); + }); + let type_surface_names = + crate::v1_compiler_emit_core_support::unique_strings(item_emit_surface_names.clone()); let field_surface_names = collect_items_field_import_surface_names( - items.clone(), + item_emit_surface_names.clone(), emit_info.clone(), - source_indices.clone(), ); let variant_payload_structs = expand_variant_payload_struct_imports( type_surface_names.clone(), @@ -8236,6 +8241,10 @@ pub fn reference_derived_use_line_plan( __result })); let emitted_source_tokens = rust_identifier_tokens(emitted_source.clone()); + let emitted_source_token_set = emitted_source_tokens.iter().cloned().fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, t: String| v1_rt::rc_map_insert(acc, t.clone(), true), + ); let candidates = Rc::new({ let mut __result = Vec::new(); for name in Rc::new({ @@ -8272,16 +8281,10 @@ pub fn reference_derived_use_line_plan( } } __found - }) || { - let mut __found = false; - for t in emitted_source_tokens.iter().cloned() { - if (t.clone() == name.clone()) { - __found = true; - break; - } - } - __found - }) { + }) || crate::v1_compiler_infer_types::emit_map_has( + emitted_source_token_set.clone(), + name.clone(), + )) { __result.push(name); } } @@ -8299,16 +8302,10 @@ pub fn reference_derived_use_line_plan( .iter() .cloned() { - if { - let mut __found = false; - for token in emitted_source_tokens.iter().cloned() { - if (token.clone() == name.clone()) { - __found = true; - break; - } - } - __found - } { + if crate::v1_compiler_infer_types::emit_map_has( + emitted_source_token_set.clone(), + name.clone(), + ) { __result.push(name); } } @@ -16118,6 +16115,46 @@ pub fn v1_call_site_equality_forwarded_param_names( } } +pub fn rust_body_is_bare_self_call( + name: String, + body: Rc, + source_indices: Rc>>, +) -> bool { + match (*body.expr_data.clone()).clone() { + ExprData::ExprCall { .. } => { + (crate::v1_std_core::qualified_last_segment(crate::v1_std_core::expr_call_func_at( + body.clone(), + source_indices.clone(), + )) == name.clone()) + } + _ => false, + } +} + +pub fn rust_seam_primitive_name(module_path: String, name: String) -> String { + match crate::std_primitive_projection::primitive_projection_row_for_declaration( + crate::std_decl_ref::decl_ref(module_path.clone(), name.clone()), + ) { + Some(row) => { + crate::std_primitive_projection::primitive_identity_runtime_name(row.primitive.clone()) + } + None => name.clone(), + } +} + +pub fn rust_host_seam_is_unrealized( + module_path: String, + name: String, + body: Rc, + source_indices: Rc>>, +) -> bool { + (rust_body_is_bare_self_call(name.clone(), body.clone(), source_indices.clone()) + && (rust_runtime_primitive_has_bridge(rust_seam_primitive_name( + module_path.clone(), + name.clone(), + )) == false)) +} + pub fn emit_fn_def( name: String, params: Rc>>, @@ -16287,6 +16324,17 @@ pub fn emit_fn_def( registry.clone(), si.clone(), ) && (use_tco.clone() == false)); + if rust_host_seam_is_unrealized( + scope.module_name.clone(), + name.clone(), + body.clone(), + si.clone(), + ) { + { + let kw = rust_items().func_keyword.clone(); + return v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(rust_visibility_prefix(), kw.clone()), " ".to_string()), crate::v1_compiler_emit::emit_ident(name.clone(), RenderTarget::Rust)), type_params_str.clone()), "(".to_string()), params_str.clone()), ")".to_string()), ret_str.clone()), " {\n".to_string()), crate::v1_compiler_emit_core_support::make_indent(1)), "panic!(\"unrealized host seam '".to_string()), name.clone()), "' in ".to_string()), scope.module_name.clone()), ": this declaration's whole body is a self-call, so it has no behaviour on this target. ".to_string()), "It compiles as a refusal rather than as recursion. Give it a row in ".to_string()), "extdeps.languages.rust.emit rt_function_registry and a body in v1.runtime_rust, or delete its consumers.\")\n}".to_string()); + } + } if use_tco.clone() { { let tco_params_str = emit_tco_params( @@ -24947,22 +24995,27 @@ pub fn emit_typed_method_call( } else { method_name_raw.clone() }; - if (method_name.clone() == "fold".to_string()) { - emit_rust_fold_method_call( - method_call_node.clone(), - fold_accumulator_type.clone(), - result_type.clone(), - receiver.clone(), - args.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - ) + let algebra_field_call = rust_callable_field_method_call( + method_name.clone(), + receiver.clone(), + args.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ); + if (algebra_field_call.clone() != None) { + match algebra_field_call.clone() { + Some(field_call) => field_call.clone(), + None => "".to_string(), + } } else { - if (method_name.clone() == "sort_by".to_string()) { - emit_rust_sort_by_method_call( + if (method_name.clone() == "fold".to_string()) { + emit_rust_fold_method_call( + method_call_node.clone(), + fold_accumulator_type.clone(), + result_type.clone(), receiver.clone(), args.clone(), registry.clone(), @@ -24972,8 +25025,8 @@ pub fn emit_typed_method_call( emit_info.clone(), ) } else { - if (method_name.clone() == "map".to_string()) { - emit_rust_map_method_call( + if (method_name.clone() == "sort_by".to_string()) { + emit_rust_sort_by_method_call( receiver.clone(), args.clone(), registry.clone(), @@ -24983,20 +25036,8 @@ pub fn emit_typed_method_call( emit_info.clone(), ) } else { - match Rc::new({ - let mut __result = Vec::new(); - for s in rust_higher_order_methods().iter().cloned() { - if (s.method_name.clone() == method_name.clone()) { - __result.push(s); - } - } - __result - }) - .first() - .cloned() - { - Some(ho_spec) => emit_rust_higher_order_method( - ho_spec.clone(), + if (method_name.clone() == "map".to_string()) { + emit_rust_map_method_call( receiver.clone(), args.clone(), registry.clone(), @@ -25004,21 +25045,33 @@ pub fn emit_typed_method_call( depth.clone(), shared_types.clone(), emit_info.clone(), - ), - None => { - if (method_name.clone() == "get".to_string()) { - emit_rust_get_method_call( - receiver.clone(), - args.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - ) - } else { - if (method_name.clone() == "with".to_string()) { - emit_rust_with_method_call( + ) + } else { + match Rc::new({ + let mut __result = Vec::new(); + for s in rust_higher_order_methods().iter().cloned() { + if (s.method_name.clone() == method_name.clone()) { + __result.push(s); + } + } + __result + }) + .first() + .cloned() + { + Some(ho_spec) => emit_rust_higher_order_method( + ho_spec.clone(), + receiver.clone(), + args.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ), + None => { + if (method_name.clone() == "get".to_string()) { + emit_rust_get_method_call( receiver.clone(), args.clone(), registry.clone(), @@ -25028,15 +25081,10 @@ pub fn emit_typed_method_call( emit_info.clone(), ) } else { - if (method_name.clone() - == "string_contains".to_string()) - { - emit_rust_generic_method_call( - "string_contains".to_string(), + if (method_name.clone() == "with".to_string()) { + emit_rust_with_method_call( receiver.clone(), args.clone(), - result_type.clone(), - true, registry.clone(), scope.clone(), depth.clone(), @@ -25044,58 +25092,26 @@ pub fn emit_typed_method_call( emit_info.clone(), ) } else { - if (method_name.clone() == "concat".to_string()) { - { - let recv_str = emit_typed_expr( - receiver.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - 1024, - ); - let arg_strs = Rc::new({ - let mut __result = Vec::new(); - for a in args.iter().cloned() { - __result.push(emit_typed_expr( - crate::v1_std_core::arg_value( - a.clone(), - ), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - 1024, - )); - } - __result - }); - let all_arg_strs = v1_rt::concat( - Rc::new(vec![recv_str.clone()]), - arg_strs.clone(), - ); - emit_nested_rt_concat( - all_arg_strs.clone(), - "".to_string(), - shared_types.clone(), - ) - } + if (method_name.clone() + == "string_contains".to_string()) + { + emit_rust_generic_method_call( + "string_contains".to_string(), + receiver.clone(), + args.clone(), + result_type.clone(), + true, + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ) } else { - if (method_name.clone() == "first".to_string()) + if (method_name.clone() == "concat".to_string()) { - emit_rust_first_method_call( - receiver.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - ) - } else { { - let recv_str_raw = emit_typed_expr( + let recv_str = emit_typed_expr( receiver.clone(), registry.clone(), scope.clone(), @@ -25104,35 +25120,76 @@ pub fn emit_typed_method_call( emit_info.clone(), 1024, ); - let recv_is_optional = (crate::v1_compiler_infer_types::resolved_type(receiver.clone()).return_cardinality.clone() == Cardinality::CardOptional); - let recv_str = if recv_is_optional - .clone() + let arg_strs = Rc::new({ + let mut __result = Vec::new(); + for a in args.iter().cloned() { + __result.push(emit_typed_expr(crate::v1_std_core::arg_value(a.clone()), registry.clone(), scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone(), 1024)); + } + __result + }); + let all_arg_strs = v1_rt::concat( + Rc::new(vec![recv_str.clone()]), + arg_strs.clone(), + ); + emit_nested_rt_concat( + all_arg_strs.clone(), + "".to_string(), + shared_types.clone(), + ) + } + } else { + if (method_name.clone() + == "first".to_string()) + { + emit_rust_first_method_call( + receiver.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ) + } else { { - v1_rt::concat(recv_str_raw.clone(), v1_rt::concat(".expect(\"fail-closed: Optional receiver for method ".to_string(), v1_rt::concat(method_name.clone(), " (empty Optional at runtime)\")".to_string()))) - } else { - recv_str_raw.clone() - }; - let first_arg_str = - emit_typed_first_arg( - args.clone(), + let recv_str_raw = emit_typed_expr( + receiver.clone(), registry.clone(), scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone(), + 1024, ); - match v1_rt::map_get(&crate::extdeps_languages_rust_emit::rust_method_templates(), method_name.clone()) { + let recv_is_optional = (crate::v1_compiler_infer_types::resolved_type(receiver.clone()).return_cardinality.clone() == Cardinality::CardOptional); + let recv_str = if recv_is_optional + .clone() + { + v1_rt::concat(recv_str_raw.clone(), v1_rt::concat(".expect(\"fail-closed: Optional receiver for method ".to_string(), v1_rt::concat(method_name.clone(), " (empty Optional at runtime)\")".to_string()))) + } else { + recv_str_raw.clone() + }; + let first_arg_str = + emit_typed_first_arg( + args.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ); + match v1_rt::map_get(&crate::extdeps_languages_rust_emit::rust_method_templates(), method_name.clone()) { Some(tmpl) => { - let bindings = v1_rt::rc_map_insert(crate::v1_compiler_emit::seed_bindings("recv".to_string(), recv_str.clone()), "arg".to_string(), first_arg_str.clone()); + let bindings = v1_rt::rc_map_insert(crate::v1_compiler_emit::seed_bindings("recv".to_string(), recv_str.clone()), "arg".to_string(), first_arg_str.clone()); let raw = crate::v1_compiler_emit_core_support::apply_named_template(tmpl.clone(), bindings.clone()); if rust_method_template_result_wraps_in_rc(method_name.clone()) { - rust_shared_wrap_ctor(raw.clone()) - } else { - raw.clone() - } + rust_shared_wrap_ctor(raw.clone()) + } else { + raw.clone() + } }, None => emit_rust_generic_method_call(method_name.clone(), receiver.clone(), args.clone(), result_type.clone(), rust_runtime_primitive_has_bridge(method_name.clone()), registry.clone(), scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone()), } + } } } } @@ -25146,13 +25203,19 @@ if rust_method_template_result_wraps_in_rc(method_name.clone()) { } } MethodSemantics::PlainMethodSemantics => { - if ((method.clone() == "get".to_string()) - && is_collection_typed_expr( - receiver.clone(), - scope.type_env.clone().source_indices.clone(), - )) + if (rust_callable_field_method_call( + method.clone(), + receiver.clone(), + args.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ) != None) { - emit_rust_get_method_call( + match rust_callable_field_method_call( + method.clone(), receiver.clone(), args.clone(), registry.clone(), @@ -25160,83 +25223,106 @@ if rust_method_template_result_wraps_in_rc(method_name.clone()) { depth.clone(), shared_types.clone(), emit_info.clone(), - ) + ) { + Some(field_call) => field_call.clone(), + None => "".to_string(), + } } else { + if ((method.clone() == "get".to_string()) + && is_collection_typed_expr( + receiver.clone(), + scope.type_env.clone().source_indices.clone(), + )) { - let recv_str = emit_typed_expr( + emit_rust_get_method_call( receiver.clone(), + args.clone(), registry.clone(), scope.clone(), depth.clone(), shared_types.clone(), emit_info.clone(), - 1024, - ); - match v1_rt::map_get( - &crate::extdeps_languages_rust_emit::rust_method_templates(), - method.clone(), - ) { - Some(tmpl) => { - let first_arg_str = emit_typed_first_arg( - args.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - ); - let bindings = v1_rt::rc_map_insert( - crate::v1_compiler_emit::seed_bindings( - "recv".to_string(), - recv_str.clone(), - ), - "arg".to_string(), - first_arg_str.clone(), - ); - let raw = - crate::v1_compiler_emit_core_support::apply_named_template( - tmpl.clone(), - bindings.clone(), + ) + } else { + { + let recv_str = emit_typed_expr( + receiver.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + 1024, + ); + match v1_rt::map_get( + &crate::extdeps_languages_rust_emit::rust_method_templates(), + method.clone(), + ) { + Some(tmpl) => { + let first_arg_str = emit_typed_first_arg( + args.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), ); - if rust_method_template_result_wraps_in_rc(method.clone()) { - rust_shared_wrap_ctor(raw.clone()) - } else { - raw.clone() - } - } - None => { - let arg_strs = Rc::new({ - let mut __result = Vec::new(); - for a in args.iter().cloned() { - __result.push(emit_typed_expr( - crate::v1_std_core::arg_value(a.clone()), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - 1024, - )); + let bindings = v1_rt::rc_map_insert( + crate::v1_compiler_emit::seed_bindings( + "recv".to_string(), + recv_str.clone(), + ), + "arg".to_string(), + first_arg_str.clone(), + ); + let raw = + crate::v1_compiler_emit_core_support::apply_named_template( + tmpl.clone(), + bindings.clone(), + ); + if rust_method_template_result_wraps_in_rc(method.clone()) { + rust_shared_wrap_ctor(raw.clone()) + } else { + raw.clone() } - __result - }); - let args_str = arg_strs.clone().join(&", ".to_string()); - v1_rt::concat( + } + None => { + let arg_strs = Rc::new({ + let mut __result = Vec::new(); + for a in args.iter().cloned() { + __result.push(emit_typed_expr( + crate::v1_std_core::arg_value(a.clone()), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + 1024, + )); + } + __result + }); + let args_str = arg_strs.clone().join(&", ".to_string()); v1_rt::concat( v1_rt::concat( v1_rt::concat( - v1_rt::concat(recv_str.clone(), ".".to_string()), - crate::v1_compiler_emit::emit_ident( - method.clone(), - RenderTarget::Rust, + v1_rt::concat( + v1_rt::concat( + recv_str.clone(), + ".".to_string(), + ), + crate::v1_compiler_emit::emit_ident( + method.clone(), + RenderTarget::Rust, + ), ), + "(".to_string(), ), - "(".to_string(), + args_str.clone(), ), - args_str.clone(), - ), - ")".to_string(), - ) + ")".to_string(), + ) + } } } } @@ -26762,6 +26848,66 @@ pub fn rust_record_field_needs_fn_rc( } } +pub fn rust_callable_field_method_call( + method_name: String, + receiver: Rc, + args: Rc>>, + registry: Rc>>, + scope: Rc, + depth: i64, + shared_types: Rc>, + emit_info: Rc, +) -> Option { + if rust_receiver_has_callable_method_field(receiver.clone(), method_name.clone(), scope.clone()) + { + { + let recv_str = emit_typed_expr_base( + receiver.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ); + let arg_strs = Rc::new({ + let mut __result = Vec::new(); + for a in args.iter().cloned() { + __result.push(emit_cloned_arg( + crate::v1_std_core::arg_value(a.clone()), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + )); + } + __result + }); + Some(v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat("(".to_string(), recv_str.clone()), + ".".to_string(), + ), + crate::v1_compiler_emit::emit_ident( + method_name.clone(), + RenderTarget::Rust, + ), + ), + ")(".to_string(), + ), + arg_strs.clone().join(&", ".to_string()), + ), + ")".to_string(), + )) + } + } else { + None + } +} + pub fn rust_receiver_has_callable_method_field( receiver: Rc, method_name: String, @@ -26773,11 +26919,14 @@ pub fn rust_receiver_has_callable_method_field( scope.type_env.clone().source_indices.clone(), receiver_type.clone(), ); - rust_record_field_needs_fn_rc( + match rust_struct_field_type_node( scope.clone(), receiver_type_name.clone(), method_name.clone(), - ) + ) { + Some(field_type) => (field_type.connective.clone() == Connective::Arrow), + None => false, + } } } diff --git a/src/v1/stage0/src/v1_compiler_infer.rs b/src/v1/stage0/src/v1_compiler_infer.rs index 79504f5b9fa..99b310179bc 100644 --- a/src/v1/stage0/src/v1_compiler_infer.rs +++ b/src/v1/stage0/src/v1_compiler_infer.rs @@ -4882,18 +4882,24 @@ pub fn direct_call_argument_inhabitance_diags( __result.extend( (*match app.matched_arg.clone() { Some(ta) => { - let actual_expr = crate::v1_std_core::arg_value(ta.clone()); - declared_type_obligation_diags( - Rc::new(DeclaredTypeObligation { - position: DeclaredTypePosition::PositionDirectCallArgument, - declared: app.formal_subst.clone(), - produced: crate::v1_compiler_infer_types::resolved_type( - actual_expr.clone(), - ), - span: actual_expr.span.clone(), - }), - scope.clone(), - ) + if type_node_is_callable(app.formal_subst.clone()) { + Rc::new(vec![]) + } else { + { + let actual_expr = crate::v1_std_core::arg_value(ta.clone()); + declared_type_obligation_diags( + Rc::new(DeclaredTypeObligation { + position: DeclaredTypePosition::PositionDirectCallArgument, + declared: app.formal_subst.clone(), + produced: crate::v1_compiler_infer_types::resolved_type( + actual_expr.clone(), + ), + span: actual_expr.span.clone(), + }), + scope.clone(), + ) + } + } } None => Rc::new(vec![]), }) diff --git a/src/v1/stage0/src/v1_compiler_runtime_rust.rs b/src/v1/stage0/src/v1_compiler_runtime_rust.rs index 7711aa64f38..a6e3c928605 100644 --- a/src/v1/stage0/src/v1_compiler_runtime_rust.rs +++ b/src/v1/stage0/src/v1_compiler_runtime_rust.rs @@ -36,7 +36,7 @@ pub fn rt_concat_trait() -> String { } pub fn rt_string_ops() -> 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(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("/// Code-point indexing over UTF-8, with the ASCII fast path bounded by `pos`\n".to_string(), "/// rather than by the whole string. A leading run of ASCII bytes makes the byte\n".to_string()), "/// offset equal the code-point offset, so nothing past `pos` is examined and the\n".to_string()), "/// per-call whole-string `s.is_ascii()` rescan is gone (STRING-INDEX-0). Cost is\n".to_string()), "/// O(min(pos, n)) -- the fallback's own cost -- never O(n) unconditionally.\n".to_string()), "/// This is the entry point for a caller holding a bare `&str` and therefore no ASCII\n".to_string()), "/// fact: it must test, and O(min(pos, n)) is the cheapest honest test. A caller that\n".to_string()), "/// holds an `RcStr` carries the fact instead and calls `RcStr::char_at`, which is\n".to_string()), "/// O(1) on ASCII text; the interpreter routes every string index that way.\n".to_string()), "/// RESIDUAL: a left-to-right walk through THIS function is still O(n^2), and a walk\n".to_string()), "/// through the carrier is linear rather than constant per string -- a cursor surface\n".to_string()), "/// that does not re-index from zero is that residual's next rung.\n".to_string()), "pub fn char_at(s: &str, pos: i64) -> String {\n".to_string()), " let pos = pos.max(0) as usize;\n".to_string()), " let bytes = s.as_bytes();\n".to_string()), " if pos >= bytes.len() { return String::new(); }\n".to_string()), " if bytes[..=pos].is_ascii() { return String::from(bytes[pos] as char); }\n".to_string()), " s.chars().nth(pos).map(|ch| ch.to_string()).unwrap_or_default()\n".to_string()), "}\n\n".to_string()), "pub fn string_length(s: &str) -> i64 {\n".to_string()), " if s.is_ascii() { s.len() as i64 } else { s.chars().count() as i64 }\n".to_string()), "}\n\n".to_string()), "/// See `char_at`: the ASCII fast path is bounded by `end`, not by the whole string.\n".to_string()), "pub fn substring(s: &str, start: i64, end: i64) -> String {\n".to_string()), " let start = start.max(0) as usize;\n".to_string()), " let end = end.max(0) as usize;\n".to_string()), " if end <= start { return String::new(); }\n".to_string()), " let bytes = s.as_bytes();\n".to_string()), " if start >= bytes.len() { return String::new(); }\n".to_string()), " let out_end = end.min(bytes.len());\n".to_string()), " if bytes[..out_end].is_ascii() {\n".to_string()), " let take_len = out_end.saturating_sub(start);\n".to_string()), " record_substring_chars_walked(s, start, take_len);\n".to_string()), " return s[start..out_end].to_string();\n".to_string()), " }\n".to_string()), " let take_len = end.saturating_sub(start);\n".to_string()), " record_substring_chars_walked(s, start, take_len);\n".to_string()), " s.chars().skip(start).take(take_len).collect()\n".to_string()), "}\n\n".to_string()), "pub fn string_contains(s: &str, sub: String) -> bool {\n".to_string()), " s.contains(&*sub)\n".to_string()), "}\n\n".to_string()), "pub fn contains(s: String, sub: String) -> bool { string_contains(&s, sub) }\n\n".to_string()), "pub fn starts_with(s: String, prefix: String) -> bool { s.starts_with(&*prefix) }\n\n".to_string()), "pub fn ends_with(s: String, suffix: String) -> bool { s.ends_with(&*suffix) }\n\n".to_string()), "pub fn trim(s: String) -> String { s.trim().to_string() }\n\n".to_string()), "pub fn count(items: Rc>) -> i64 { items.len() as i64 }\n\n".to_string()), "pub fn str_eq(a: String, b: String) -> bool { a == b }\n\n".to_string()), "pub fn to_string(value: i64) -> String { value.to_string() }\n\n".to_string()), "/// RFC 3629 UTF-8 decode of a byte vector. Fail-closed on invalid UTF-8.\n".to_string()), "pub fn utf8_decode_bytes(bytes: &[u8]) -> Result {\n".to_string()), " String::from_utf8(bytes.to_vec()).map_err(|e| format!(\"invalid UTF-8 in access payload: {}\", e))\n".to_string()), "}\n\n".to_string()), "pub fn clamp(val: i64, min_val: i64, max_val: i64) -> i64 {\n".to_string()), " val.clamp(min_val, max_val)\n".to_string()), "}\n\n".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(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("/// Code-point indexing over UTF-8, with the ASCII fast path bounded by `pos`\n".to_string(), "/// rather than by the whole string. A leading run of ASCII bytes makes the byte\n".to_string()), "/// offset equal the code-point offset, so nothing past `pos` is examined and the\n".to_string()), "/// per-call whole-string `s.is_ascii()` rescan is gone (STRING-INDEX-0). Cost is\n".to_string()), "/// O(min(pos, n)) -- the fallback's own cost -- never O(n) unconditionally.\n".to_string()), "/// This is the entry point for a caller holding a bare `&str` and therefore no ASCII\n".to_string()), "/// fact: it must test, and O(min(pos, n)) is the cheapest honest test. A caller that\n".to_string()), "/// holds an `RcStr` carries the fact instead and calls `RcStr::char_at`, which is\n".to_string()), "/// O(1) on ASCII text; the interpreter routes every string index that way.\n".to_string()), "/// RESIDUAL: a left-to-right walk through THIS function is still O(n^2), and a walk\n".to_string()), "/// through the carrier is linear rather than constant per string -- a cursor surface\n".to_string()), "/// that does not re-index from zero is that residual's next rung.\n".to_string()), "pub fn char_at(s: &str, pos: i64) -> String {\n".to_string()), " let pos = pos.max(0) as usize;\n".to_string()), " let bytes = s.as_bytes();\n".to_string()), " if pos >= bytes.len() { return String::new(); }\n".to_string()), " if bytes[..=pos].is_ascii() { return String::from(bytes[pos] as char); }\n".to_string()), " s.chars().nth(pos).map(|ch| ch.to_string()).unwrap_or_default()\n".to_string()), "}\n\n".to_string()), "pub fn string_length(s: &str) -> i64 {\n".to_string()), " if s.is_ascii() { s.len() as i64 } else { s.chars().count() as i64 }\n".to_string()), "}\n\n".to_string()), "/// The two symbol bridges. `Symbol` is declared to realize as `String` on this target\n".to_string()), "/// (extdeps.languages.rust.types), so interning and its inverse are both the identity\n".to_string()), "/// HERE and nowhere else: a target whose Symbol is a table index needs a real table, and\n".to_string()), "/// its registry rows would say so. These exist because the .dag declarations are\n".to_string()), "/// self-calls -- host seams -- and emitting a self-call produces a function that compiles\n".to_string()), "/// and never returns (std.primitive_projection symbol_lexeme_seam_disposition_note).\n".to_string()), "pub fn symbol_lexeme(sym: String) -> String {\n".to_string()), " sym\n".to_string()), "}\n\n".to_string()), "pub fn symbol_intern_lexeme(lexeme: String) -> String {\n".to_string()), " lexeme\n".to_string()), "}\n\n".to_string()), "/// See `char_at`: the ASCII fast path is bounded by `end`, not by the whole string.\n".to_string()), "pub fn substring(s: &str, start: i64, end: i64) -> String {\n".to_string()), " let start = start.max(0) as usize;\n".to_string()), " let end = end.max(0) as usize;\n".to_string()), " if end <= start { return String::new(); }\n".to_string()), " let bytes = s.as_bytes();\n".to_string()), " if start >= bytes.len() { return String::new(); }\n".to_string()), " let out_end = end.min(bytes.len());\n".to_string()), " if bytes[..out_end].is_ascii() {\n".to_string()), " let take_len = out_end.saturating_sub(start);\n".to_string()), " record_substring_chars_walked(s, start, take_len);\n".to_string()), " return s[start..out_end].to_string();\n".to_string()), " }\n".to_string()), " let take_len = end.saturating_sub(start);\n".to_string()), " record_substring_chars_walked(s, start, take_len);\n".to_string()), " s.chars().skip(start).take(take_len).collect()\n".to_string()), "}\n\n".to_string()), "pub fn string_contains(s: &str, sub: String) -> bool {\n".to_string()), " s.contains(&*sub)\n".to_string()), "}\n\n".to_string()), "pub fn contains(s: String, sub: String) -> bool { string_contains(&s, sub) }\n\n".to_string()), "pub fn starts_with(s: String, prefix: String) -> bool { s.starts_with(&*prefix) }\n\n".to_string()), "pub fn ends_with(s: String, suffix: String) -> bool { s.ends_with(&*suffix) }\n\n".to_string()), "pub fn trim(s: String) -> String { s.trim().to_string() }\n\n".to_string()), "pub fn count(items: Rc>) -> i64 { items.len() as i64 }\n\n".to_string()), "pub fn str_eq(a: String, b: String) -> bool { a == b }\n\n".to_string()), "pub fn to_string(value: i64) -> String { value.to_string() }\n\n".to_string()), "/// RFC 3629 UTF-8 decode of a byte vector. Fail-closed on invalid UTF-8.\n".to_string()), "pub fn utf8_decode_bytes(bytes: &[u8]) -> Result {\n".to_string()), " String::from_utf8(bytes.to_vec()).map_err(|e| format!(\"invalid UTF-8 in access payload: {}\", e))\n".to_string()), "}\n\n".to_string()), "pub fn clamp(val: i64, min_val: i64, max_val: i64) -> i64 {\n".to_string()), " val.clamp(min_val, max_val)\n".to_string()), "}\n\n".to_string()) } pub fn rt_collection_ops() -> String { diff --git a/src/v1/stage0/src/v1_rt.rs b/src/v1/stage0/src/v1_rt.rs index 97af46d127e..30f3c637d47 100644 --- a/src/v1/stage0/src/v1_rt.rs +++ b/src/v1/stage0/src/v1_rt.rs @@ -309,6 +309,20 @@ pub fn string_length(s: &str) -> i64 { } } +/// The two symbol bridges. `Symbol` is declared to realize as `String` on this target +/// (extdeps.languages.rust.types), so interning and its inverse are both the identity +/// HERE and nowhere else: a target whose Symbol is a table index needs a real table, and +/// its registry rows would say so. These exist because the .dag declarations are +/// self-calls -- host seams -- and emitting a self-call produces a function that compiles +/// and never returns (std.primitive_projection symbol_lexeme_seam_disposition_note). +pub fn symbol_lexeme(sym: String) -> String { + sym +} + +pub fn symbol_intern_lexeme(lexeme: String) -> String { + lexeme +} + /// See `char_at`: the ASCII fast path is bounded by `end`, not by the whole string. pub fn substring(s: &str, start: i64, end: i64) -> String { let start = start.max(0) as usize; From aeded616fcf17a5476152fbc0f9f0a8c729fe9f3 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 14:14:45 +0000 Subject: [PATCH 20/30] WIP tail classes --- ...d_call_target_realization_witness_test.dag | 99 +++++++++++++ src/v1/05_emit_rust.dag | 133 ++++++++++++++++-- 2 files changed, 224 insertions(+), 8 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index c119cfcdccc..cc462a5376e 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -255,3 +255,102 @@ test fn w_map_receiver_operation_is_not_read_as_a_callable_field() -> Bool { [".map_keys)("] ) } + +// --------------------------------------------------------------------------------------------- +// THE TAIL CLASSES: the fifteen rustc refusals that remained on the 00_compile closure once the +// three families above were closed, one discriminating row per emitter defect. Each row's +// must_not_contain is the exact malformed spelling the emitter produced, so a revert of that one +// repair reddens exactly that row. +// --------------------------------------------------------------------------------------------- + +// WITNESS CARRIER, THE DISCRIMINATING RED. A Holds value bound through a NESTED record pattern can +// reach emission with its produced identity erased; the turbofish then rendered the erasure itself: +// `Witness::::Holds`. The enclosing fn's declared return +// is the carrier authority and must be what the arm falls back to. +test fn w_witness_carrier_falls_back_to_the_fn_return_when_the_value_identity_is_erased() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.witness_carrier_probe\nimport std.types { Int }\nimport std.algebra { Cons, Empty }\nimport v2.std.algebra { fold_list, list_snoc_item }\nimport v2.std.witness { Holds, Violates, Witness }\nimport v2.std.diagnostic { Diagnostic }\ntype Progress { edges: List, index: Int }\nfn step(p: Witness, x: Int) -> Witness { match p { Holds { value: Progress { edges: es, index: i } } => Holds { value: Progress { edges: list_snoc_item(xs: es, item: x), index: i + 1 } } Violates { diagnostic: d } => Violates { diagnostic: d } } }\nfn probe(xs: List) -> Witness> { match fold_list(xs: xs, empty: Holds { value: Progress { edges: Empty, index: 0 } }, cons: fn(p, x) { step(p: p, x: x) }) { Holds { value: Progress { edges: result, index: _ } } => Holds { value: result } Violates { diagnostic: d } => Violates { diagnostic: d } } }\n", + "src/test_claim_witness_carrier_probe.rs", + ["Witness::<"], + ["UNRESOLVED_CompilerError"] + ) +} + +// FOLD ACCUMULATOR, THE DISCRIMINATING RED. A fold whose init is empty_map() took the Map +// declaration's own formals as its accumulator and wrote them into the turbofish: +// `v1_rt::rc_empty_map::()`. The fn's declared Map return is the resolved +// accumulator and must be what the init renders from. +test fn w_fold_empty_map_init_renders_the_resolved_accumulator_not_the_declaration_formals() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.fold_accumulator_probe\nimport std.types { Int, String, Map }\nimport v2.std.node { Symbol }\nimport v2.std.collection { empty_map, map_insert }\ntype Row { field: Symbol, carrier: Symbol }\nfn rows() -> List { [Row { field: ^a, carrier: ^b }] }\nfn probe() -> Map { fold(rows(), init: empty_map(), f: fn(acc, row) { map_insert(m: acc, key: row.field, value: row.carrier) }) }\n", + "src/test_claim_fold_accumulator_probe.rs", + ["rc_empty_map::<"], + ["rc_empty_map::"] + ) +} + +// LAMBDA PARAMETER ANNOTATION, THE DISCRIMINATING RED. A closure parameter whose inferred type +// carries a formal no fn generic binds (`FreeMonoid`) was annotated with it verbatim, a type the +// closure cannot name. The annotation must decline exactly as the fold element annotation does. +test fn w_lambda_param_annotation_declines_a_spurious_generic() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.lambda_annotation_probe\nimport std.types { Bool }\nimport std.algebra { Cons, Empty }\nimport v2.std.node { Symbol }\nfn has(xs: List, s: Symbol) -> Bool { match xs { Empty => false Cons { head: h, tail: t } => if h == s { true } else { has(xs: t, s: s) } } }\nfn probe(hits: List, accepted: List) -> Bool { match hits { Empty => false Cons { head: first_hit, tail: rest_hits } => fold(Cons { head: first_hit, tail: rest_hits }, init: true, f: fn(acc, a) { acc && has(xs: accepted, s: a) }) } }\n", + "src/test_claim_lambda_annotation_probe.rs", + ["|acc: bool"], + ["FreeMonoid>|"] + ) +} + +// ZERO-PARAMETER ALIAS, THE DISCRIMINATING RED. An alias over a parameterized type, referenced as +// the return of an arrow type, rendered with the arguments of what it abbreviates: +// `Gate = Rc Outc>>>` (E0107, with the E0391 variance cycle rustc +// reports beside it). The alias is zero-parameter and must render bare. +test fn w_zero_param_alias_in_an_arrow_return_renders_without_its_rhs_arguments() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.alias_arrow_probe\nimport std.types { Int }\nimport v2.std.witness { Witness }\nimport v2.std.diagnostic { Outcome }\nimport v2.std.node { Node }\ntype Outc = Outcome>\ntype Gate = fn(Int) -> Outc\ntype Lens { gate: Gate }\n", + "src/test_claim_alias_arrow_probe.rs", + ["-> Outc>"], + ["Outc<"] + ) +} + +// ARROW RETURN BINDING, THE DISCRIMINATING RED. An arrow type's return rendered through the +// target-generic renderer, which never reads an applied-type binding, so `fn(Int) -> Outcome>` +// dropped the inner binding: `Rc>>` (E0107 missing generics). The Rust renderer +// honours the binding and must be what an arrow's positions render through. +test fn w_arrow_return_type_keeps_its_applied_binding() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.arrow_binding_probe\nimport std.types { Int, String }\nimport v2.std.diagnostic { Outcome }\ntype Box2 { v: T }\nfn probe() -> fn(Int) -> Outcome> { fn(n) { Outcome::Accepted { value: Box2 { v: \"x\" } } } }\n", + "src/test_claim_arrow_binding_probe.rs", + ["Box2"], + ["Rc>"] + ) +} + +// QUALIFIED TYPE REFERENCE, THE DISCRIMINATING RED. A field typed `std.determinism.Determinism` +// with no import renders as bare `Determinism`, and the use-line derivation collected the DOTTED +// spelling, which is never an emitted token, so the module referenced a name it never imported. +// The leaf must earn its use-line from the qualified registry row. +test fn w_qualified_type_reference_earns_the_leaf_use_line() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.qualified_type_ref_probe\nimport std.types { String }\ntype Fact { signature: String, classification: std.determinism.Determinism }\nfn probe(f: Fact) -> std.determinism.Determinism { f.classification }\n", + "src/test_claim_qualified_type_ref_probe.rs", + ["use crate::std_determinism::Determinism"], + ["std.determinism.Determinism"] + ) +} + +// SERVICE OP WITHOUT A REALIZATION, THE DISCRIMINATING RED. `Filesystem.Read(path:)` inside a fn +// the signature authority judged service-free emitted `filesystem.read(path).await?` -- an unbound +// name in a non-async fn, the only `.await?` in the whole closure. It is a host seam with no +// realization in this target and must emit the generated refusal body naming the seam. The realized +// arm has no positive control here because no source in the corpus spells a receiver the signature +// authority accepts; that absence is recorded in rust_unrealized_service_op_refusal's note. +test fn w_service_op_in_a_service_free_fn_refuses_instead_of_awaiting_an_unbound_binding() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.service_op_probe\nimport std.types { String }\nimport extdeps.filesystem.filesystem_io { Filesystem }\nfn probe(path: String) -> String { let read = Filesystem.Read(path: path)\n read.content }\n", + "src/test_claim_service_op_probe.rs", + ["unrealized host seam: service op Filesystem.Read"], + [".await?"] + ) +} diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index dc7dfff8dd1..e51f54fb110 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -41,7 +41,7 @@ import v1.std.core { match_scrutinee, match_arm_nodes, if_condition, if_then_branch, if_else_branch, index_base, index_expr, slice_base, slice_start, slice_end, cast_target, cast_expr, return_value, binop_left, binop_right, no_span, with_required_cardinality, Connective, Conj, Disj, - NoConnective, Cardinality, Required, CardOptional, is_rest_transport, + NoConnective, Arrow, Cardinality, Required, CardOptional, is_rest_transport, transport_base_path, empty_intern_table } @@ -88,7 +88,7 @@ import v1.compiler.closure_stub_v2_std_integer_rust { closure_stub_v2_std_intege import v1.compiler.closure_stub_v2_std_text_rust { closure_stub_v2_std_text_source } import v1.compiler.coercion { coerce_primitive_type, is_copy, lookup_checkpoint, type_reference_decl_file, - rust_seed_host_numeric_alias + rust_seed_host_numeric_alias, target_callable } import v1.compiler.trait_derive_emit { v1_emit_enum_derives, @@ -226,6 +226,33 @@ fn render_rust_type(n: Node, shared_types: Set, source_indices: Map Outcome>` came out as +// `Rc Rc>>>` -- the inner binding dropped (E0107 missing +// generics for struct `Medium`, v2.compiler.compile stage_translate). The callable template and the +// void arm are the same rows render_node_type consumes; only the per-position renderer changes. +fn render_rust_arrow_type(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { + let repr = target_callable(target: Rust) + let param_strs = n.params |> map(p => render_rust_type(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices, emit_info: emit_info)) + let param_str = param_strs |> join(separator: repr.param_separator) + let spec = language_spec(target: Rust) + let ret_str = match n.inferred { + Present { value: Resolved { node: rt } } => render_rust_type(n: rt, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + _ => spec.void_type + } + match spec.callable_type_template { + Present { value: t } => replace(replace(t, "\{params\}", param_str), "\{return\}", ret_str) + Absent => + if ret_str == "" { + replace(replace(repr.template, concat(repr.return_separator, "\{return\}"), ""), "\{params\}", param_str) + } else { + replace(replace(repr.template, "\{params\}", param_str), "\{return\}", ret_str) + } + } +} + fn render_rust_type_without_applied_binding(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } if is_host_optional_carrier_type(n: n, source_indices: source_indices) { @@ -234,7 +261,18 @@ fn render_rust_type_without_applied_binding(n: Node, shared_types: Set, if is_host_diagnostics_carrier_type(n: n, source_indices: source_indices) { return render_rust_diagnostics_carrier_applied(shared_types: shared_types) } - if n.connective == NoConnective && n.children |> count > 0 && !is_container_type(name: authored_name_at(source_indices: source_indices, node: n)) { + if n.connective == Arrow { + render_rust_arrow_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + } else if n.connective == NoConnective && n.children |> count > 0 && !is_container_type(name: authored_name_at(source_indices: source_indices, node: n)) && closed_alias_peels_zero_param(env: emit_info.fn_type_env, n: n) { + // A ZERO-PARAMETER ALIAS NEVER TAKES THE ARGUMENTS OF WHAT IT ABBREVIATES. The resolver hands an + // alias reference back carrying its right-hand side's children, and rendering name-plus-children + // wrote `CompileLensOutcome>>>` for `type CompileLensOutcome = + // Outcome>` (E0107, and the E0391 variance cycle rustc reports beside it). The + // fn-signature renderer already answers this position bare via closed_alias_peels_zero_param; + // this is the same verdict asked at the expression-type position. + let leaf = qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: n)) + render_rust_shared_type_with_optional(n: n, type_name: leaf, rendered: leaf, shared_types: shared_types) + } else if n.connective == NoConnective && n.children |> count > 0 && !is_container_type(name: authored_name_at(source_indices: source_indices, node: n)) { render_rust_applied_via_emit_info(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) } else if node_is_set_collection(n: n, source_indices: source_indices) { match n.children |> first { @@ -682,7 +720,18 @@ fn rust_witness_applied_type_arg_node(type_node: Node, source_indices: Map::Holds { .. }`, one site on the +// 00_compile closure (v2.std.grammar derive_grammar_relation_token_edges_recursive). The fn's return +// type `Witness>` was present the whole time and is the authority for the arm's carrier; +// an erased first source must DECLINE so the second is consulted, never render its own refusal. fn rust_witness_carrier_from_type_node(type_node: Node, shared_types: Set, emit_info: EmitGraphInfo, source_indices: Map) -> String? { + if type_node.inferred != none && is_compiler_error(inferred: type_node.inferred.value) { return none } if type_node_has_unbound_type_variable(n: type_node, generic_param_names: emit_info.fn_generic_param_names, source_indices: source_indices) { return none } let peeled = rust_peel_all_rc_type_node(type_node: type_node, source_indices: source_indices) if qualified_last_segment(name: peeled.name) == "Witness" { @@ -1425,7 +1474,10 @@ fn render_rust_alias_rhs_type(n: Node, generic_param_names: List, shared } } } else { - render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: empty_emit_graph_info()) + // The env travels: an alias right-hand side that is an Arrow renders its return through + // render_rust_type, and the zero-param-alias verdict there is asked of emit_info.fn_type_env. An + // empty env answered ClosedAliasBindingAbsent for every alias and the arm could never fire. + render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info_with_fn_type_context(emit_info: empty_emit_graph_info(), generic_param_names: generic_param_names, env: scope.type_env)) } } @@ -4095,6 +4147,7 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< let value_names = unique_strings(items: items |> flat_map(item => collect_value_ref_names(n: item, source_indices: source_indices, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum))) let item_emit_surface_names = items |> flat_map(item => collect_item_emit_surface_names(item: item, source_indices: source_indices, emit_info: emit_info)) let type_surface_names = unique_strings(items: item_emit_surface_names) + let qualified_surface_leaves = qualified_type_surface_leaf_candidates(names: type_surface_names, registry: registry) let field_surface_names = collect_items_field_import_surface_names(surface_names: item_emit_surface_names, emit_info: emit_info) let variant_payload_structs = expand_variant_payload_struct_imports(names: type_surface_names, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum) let emitter_attested_anon_heads = unique_strings(items: items |> flat_map(item => collect_anonymous_record_lit_heads(n: item, source_indices: source_indices, type_summaries: emit_info.type_summaries))) @@ -4102,7 +4155,7 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< let emitted_source_tokens = rust_identifier_tokens(s: emitted_source) let emitted_source_token_set = emitted_source_tokens |> fold(init: empty_map(), f: (acc, t) => map_insert(acc, t, true)) - let candidates = unique_strings(items: concat(concat(concat(concat(concat(unlisted_type_names, value_names), type_surface_names), field_surface_names), variant_payload_structs), realized_surface_names)) + let candidates = unique_strings(items: concat(concat(concat(concat(concat(concat(unlisted_type_names, value_names), type_surface_names), qualified_surface_leaves), field_surface_names), variant_payload_structs), realized_surface_names)) |> filter(name => reference_derived_candidate_authored(module_source: module_source, name: name, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum) || emitter_attested_anon_heads |> any(h => h == name) @@ -4161,6 +4214,33 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< } } +// A QUALIFIED TYPE REFERENCE REACHES EMISSION AS ITS LEAF AND NEEDS THE LEAF'S USE-LINE. The type +// renderers spell `std.determinism.Determinism` as bare `Determinism` (rust_fn_sig_leaf_name), and +// the surface walk collects the DOTTED spelling -- which is never an identifier token in the emitted +// source, so the candidate filter dropped it before any disposition was assigned and the module +// referenced a name it never imported (E0425 cannot find type `Determinism`, v2.std.determinism, +// two sites). The leaf is admitted as a candidate only when the qualified registry row resolves it +// AND the bare row names the SAME declaring module: the downstream lookups are bare-keyed and +// last-write-wins, and a leaf whose bare row points elsewhere would import a homonym from the wrong +// provider. That disagreement stays a loud unresolved name rather than a fabricated use-line. +fn qualified_type_surface_leaf_candidates(names: List, registry: Map) -> List { + names |> flat_map(name => + if !string_contains(s: name, pattern: ".") { [] } else { + let leaf = qualified_last_segment(name: name) + match map_get(registry, name) { + Present { value: qualified_info } => + if is_duplicate_qualified_item_registry_marker(info: qualified_info) { [] } else { + match map_get(registry, leaf) { + Present { value: bare_info } => if bare_info.module_name == qualified_info.module_name { [leaf] } else { [] } + Absent => [] + } + } + Absent => [] + } + } + ) +} + fn reference_derived_use_lines(items: List, unlisted_type_names: List, this_module_name: String, registry: Map, emit_info: EmitGraphInfo, local_type_names: List, already_imported_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, shared_types: Set, emitted_source: String) -> List { let plan = reference_derived_use_line_plan(items: items, unlisted_type_names: unlisted_type_names, this_module_name: this_module_name, registry: registry, emit_info: emit_info, local_type_names: local_type_names, already_imported_names: already_imported_names, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index, shared_types: shared_types, emitted_source: emitted_source) plan.lines @@ -9912,7 +9992,16 @@ fn lambda_param_type_strs(params: List, param_nodes: List, fallbac } else if type_node_has_closure_unbound_generic_atom(n: param_type, generic_param_names: emit_info.fn_generic_param_names, env: type_env, source_indices: source_indices) { none } else { - Present { value: render_rust_type(n: param_type, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) } + // The same admission the fold arm applies to its element annotation + // (fold_elem_type_str): a rendered `FreeMonoid` whose T is no fn generic names a + // type this closure cannot spell, and an annotation that names it is refused by rustc + // (E0425 cannot find type `T`, v2.lens.mandatory_tag on the 00_compile closure). The + // node-grain check above missed it because the formal's spelling resolves to SOME + // binding in the whole-pool env; the rendered-string check is the one authority both + // arms consult, so the two cannot disagree. + let rendered = render_rust_type(n: param_type, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + if rust_fold_rendered_type_has_any_spurious_generic(type_str: rendered, generic_param_names: emit_info.fn_generic_param_names) { none } + else { Present { value: rendered } } } _ => none } @@ -10012,7 +10101,16 @@ fn emit_rust_fold_method_call(method_call_node: Node, fold_accumulator_type: Nod let is_under_resolved_list = node_is_element_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_set_collection(n: acc_type, source_indices: scope.type_env.source_indices) && acc_type.children |> count == 0 let is_under_resolved_set = node_is_set_collection(n: acc_type, source_indices: scope.type_env.source_indices) && (acc_type.children |> count == 0 || acc_children_have_unit) let is_under_resolved_non_collection = !node_is_keyed_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_element_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_collection(n: acc_type, source_indices: scope.type_env.source_indices) - if is_under_resolved_map || is_under_resolved_list || is_under_resolved_set || is_under_resolved_non_collection { + // A DECLARATION'S OWN PARAMETER NAMES ARE NOT A RESOLVED ACCUMULATOR. fold_accumulator_type can + // arrive as the container declaration's parametric shape -- Map with K and V the + // declaration's formals, bound to nothing at this call -- and the four shape tests above all + // read that as resolved (two children, neither unit-like). The init arm then wrote the formals + // straight into a turbofish, `v1_rt::rc_empty_map::()`, four sites on the 00_compile + // closure (v2.lens.unit_modeling) while the lambda beside it had already fallen back to `_`. + // The contextual method result type IS the resolved accumulator here, so a shape whose atoms are + // unbound in the closure scope is under-resolved exactly like an empty one. + let is_under_resolved_generic = type_node_has_closure_unbound_generic_atom(n: acc_type, generic_param_names: emit_info.fn_generic_param_names, env: scope.type_env, source_indices: scope.type_env.source_indices) + if is_under_resolved_map || is_under_resolved_list || is_under_resolved_set || is_under_resolved_non_collection || is_under_resolved_generic { match contextual_acc_type { Present { value: concrete_type } => concrete_type Absent => acc_type @@ -10383,9 +10481,28 @@ fn emit_rust_generic_method_call(method_name: String, receiver: Node, args: List } } +// TWO AUTHORITIES DECIDED ONE SERVICE CALL, AND THE EMISSION FOLLOWED THE ONE THAT DOES NOT REALIZE. +// The Rust realization of a service op is the SIGNATURE fact: ItemInfo.service_names, computed by +// collect_typed_service_calls over is_typed_service_call_receiver, which makes the fn async, binds +// the service as a parameter, and puts `.await?` on every caller. The method-call arm keyed on +// ServiceMethodSemantics alone and wrote `filesystem.read(path).await?` into a fn the signature +// authority had judged service-free -- an unbound name inside a non-async fn (E0425 + E0728, two +// sites in v2.compiler.source_authority, and the ONLY `.await?` in the whole emitted closure). That +// is a fabricated realization. The arm now asks the same predicate the signature asks, so the two +// agree by construction; where it declines, the op is a host seam with no realization in this +// target and emits the generated refusal body the seam ruling prescribes -- a panic naming the seam, +// never a call into a binding that does not exist. The realized arm is currently UNINHABITED by +// the corpus (no `.dag` source in the seed or the closure spells a receiver the predicate accepts), +// so its positive control is not authorable today; that is recorded, not papered over. +fn rust_unrealized_service_op_refusal(service_name: String, method: String, module_name: String) -> String { + concat("panic!(\"unrealized host seam: service op ", service_name, ".", method, " in ", module_name, ": the Rust realization binds a service only through an async fn parameter, and this function declares none\")") +} + fn emit_typed_method_call(method_call_node: Node, receiver: Node, method: String, args: List, result_type: InferredNode?, method_semantics: MethodSemantics?, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { if method_semantics != none { match method_semantics.value { - ServiceMethodSemantics { service_name: svc_name, op_params: op_params } => { + ServiceMethodSemantics { service_name: svc_name, op_params: op_params } => if !is_typed_service_call_receiver(receiver: receiver, source_indices: scope.type_env.source_indices) { + rust_unrealized_service_op_refusal(service_name: svc_name, method: method, module_name: scope.module_name) + } else { let var_name = service_var_name(service_name: svc_name) let si = scope.type_env.source_indices let filled_args = fill_op_default_args(ordered: args, op_params: op_params, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) From 4b57ad1cca56a3e57fe163a1177b737a1a7a3b20 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 14:22:26 +0000 Subject: [PATCH 21/30] WIP: if-equals-variant parses as a record literal; name the predicate --- src/v1/05_emit_rust.dag | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index e51f54fb110..c3319c15bd3 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -233,6 +233,11 @@ fn render_rust_type(n: Node, shared_types: Set, source_indices: Map Rc>>>` -- the inner binding dropped (E0107 missing // generics for struct `Medium`, v2.compiler.compile stage_translate). The callable template and the // void arm are the same rows render_node_type consumes; only the per-position renderer changes. +// Named rather than inlined because `if x == Variant {` parses as a record literal in .dag. +fn rust_type_node_is_arrow(n: Node) -> Bool { + n.connective == Arrow +} + fn render_rust_arrow_type(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { let repr = target_callable(target: Rust) let param_strs = n.params |> map(p => render_rust_type(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices, emit_info: emit_info)) @@ -261,7 +266,7 @@ fn render_rust_type_without_applied_binding(n: Node, shared_types: Set, if is_host_diagnostics_carrier_type(n: n, source_indices: source_indices) { return render_rust_diagnostics_carrier_applied(shared_types: shared_types) } - if n.connective == Arrow { + if rust_type_node_is_arrow(n: n) { render_rust_arrow_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) } else if n.connective == NoConnective && n.children |> count > 0 && !is_container_type(name: authored_name_at(source_indices: source_indices, node: n)) && closed_alias_peels_zero_param(env: emit_info.fn_type_env, n: n) { // A ZERO-PARAMETER ALIAS NEVER TAKES THE ARGUMENTS OF WHAT IT ABBREVIATES. The resolver hands an From dc04b9d24453c7729cfc4db894cd370ff134ae82 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 14:26:20 +0000 Subject: [PATCH 22/30] WIP: annotations at module-item grain --- src/v1/05_emit_rust.dag | 52 ++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index c3319c15bd3..7d529fff27b 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -258,6 +258,13 @@ fn render_rust_arrow_type(n: Node, shared_types: Set, source_indices: Ma } } +// ZERO-PARAMETER ALIAS AT THE EXPRESSION-TYPE POSITION (the closed_alias_peels_zero_param arm below): +// A ZERO-PARAMETER ALIAS NEVER TAKES THE ARGUMENTS OF WHAT IT ABBREVIATES. The resolver hands an +// alias reference back carrying its right-hand side's children, and rendering name-plus-children +// wrote `CompileLensOutcome>>>` for `type CompileLensOutcome = +// Outcome>` (E0107, and the E0391 variance cycle rustc reports beside it). The +// fn-signature renderer already answers this position bare via closed_alias_peels_zero_param; +// this is the same verdict asked at the expression-type position. fn render_rust_type_without_applied_binding(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } if is_host_optional_carrier_type(n: n, source_indices: source_indices) { @@ -269,12 +276,6 @@ fn render_rust_type_without_applied_binding(n: Node, shared_types: Set, if rust_type_node_is_arrow(n: n) { render_rust_arrow_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) } else if n.connective == NoConnective && n.children |> count > 0 && !is_container_type(name: authored_name_at(source_indices: source_indices, node: n)) && closed_alias_peels_zero_param(env: emit_info.fn_type_env, n: n) { - // A ZERO-PARAMETER ALIAS NEVER TAKES THE ARGUMENTS OF WHAT IT ABBREVIATES. The resolver hands an - // alias reference back carrying its right-hand side's children, and rendering name-plus-children - // wrote `CompileLensOutcome>>>` for `type CompileLensOutcome = - // Outcome>` (E0107, and the E0391 variance cycle rustc reports beside it). The - // fn-signature renderer already answers this position bare via closed_alias_peels_zero_param; - // this is the same verdict asked at the expression-type position. let leaf = qualified_last_segment(name: authored_name_at(source_indices: source_indices, node: n)) render_rust_shared_type_with_optional(n: n, type_name: leaf, rendered: leaf, shared_types: shared_types) } else if n.connective == NoConnective && n.children |> count > 0 && !is_container_type(name: authored_name_at(source_indices: source_indices, node: n)) { @@ -1388,6 +1389,10 @@ Fix: route on the TERMINAL segment via qualified_last_segment (v1.std.core, the The v2 corpus authors qualified names in type position only rarely today, which is why one line carried this much weight; the point of fixing the renderer rather than editing that one declaration is that the next qualified name must not reintroduce it (DESIGN: do not cement the seed's accidents)." +// THE FINAL else ARM CARRIES THE MODULE ENV: +// The env travels: an alias right-hand side that is an Arrow renders its return through +// render_rust_type, and the zero-param-alias verdict there is asked of emit_info.fn_type_env. An +// empty env answered ClosedAliasBindingAbsent for every alias and the arm could never fire. fn render_rust_alias_rhs_type(n: Node, generic_param_names: List, shared_types: Set, source_indices: Map, scope: InferScope, imports: List, registry: Map, module_name: String, export_sets: Map>, typed_modules: List, module_index: ModuleIndex, variant_to_enum: Map) -> String { if is_where_refinement_type(ty: n) { match n.children |> first { @@ -1479,9 +1484,6 @@ fn render_rust_alias_rhs_type(n: Node, generic_param_names: List, shared } } } else { - // The env travels: an alias right-hand side that is an Arrow renders its return through - // render_rust_type, and the zero-param-alias verdict there is asked of emit_info.fn_type_env. An - // empty env answered ClosedAliasBindingAbsent for every alias and the arm could never fire. render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info_with_fn_type_context(emit_info: empty_emit_graph_info(), generic_param_names: generic_param_names, env: scope.type_env)) } } @@ -9979,6 +9981,14 @@ fn lambda_scope_from_children(scope: InferScope, params: List, param_nod ) } +// THE RENDERED-STRING ADMISSION ON AN INFERRED PARAMETER TYPE: +// The same admission the fold arm applies to its element annotation +// (fold_elem_type_str): a rendered `FreeMonoid` whose T is no fn generic names a +// type this closure cannot spell, and an annotation that names it is refused by rustc +// (E0425 cannot find type `T`, v2.lens.mandatory_tag on the 00_compile closure). The +// node-grain check above missed it because the formal's spelling resolves to SOME +// binding in the whole-pool env; the rendered-string check is the one authority both +// arms consult, so the two cannot disagree. fn lambda_param_type_strs(params: List, param_nodes: List, fallback_types: List, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo, fold_acc_uses_fallback: Bool, type_env: TypeEnv) -> List { params |> enumerate |> map(pair => let idx = pair.first @@ -9997,13 +10007,6 @@ fn lambda_param_type_strs(params: List, param_nodes: List, fallbac } else if type_node_has_closure_unbound_generic_atom(n: param_type, generic_param_names: emit_info.fn_generic_param_names, env: type_env, source_indices: source_indices) { none } else { - // The same admission the fold arm applies to its element annotation - // (fold_elem_type_str): a rendered `FreeMonoid` whose T is no fn generic names a - // type this closure cannot spell, and an annotation that names it is refused by rustc - // (E0425 cannot find type `T`, v2.lens.mandatory_tag on the 00_compile closure). The - // node-grain check above missed it because the formal's spelling resolves to SOME - // binding in the whole-pool env; the rendered-string check is the one authority both - // arms consult, so the two cannot disagree. let rendered = render_rust_type(n: param_type, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) if rust_fold_rendered_type_has_any_spurious_generic(type_str: rendered, generic_param_names: emit_info.fn_generic_param_names) { none } else { Present { value: rendered } } @@ -10092,6 +10095,15 @@ fn emit_typed_fold_lambda(lambda_expr: Node, acc_type_str: String, elem_type_str // instead would restate it, and would then have to be kept in step with any future change to the strip // -- reintroducing the shape of this defect while fixing this instance of it. `_` is also the device // already used for elem_render_has_spurious_generic a few bindings earlier. +// THE UNDER-RESOLVED-GENERIC ACCUMULATOR ARM (is_under_resolved_generic below): +// A DECLARATION'S OWN PARAMETER NAMES ARE NOT A RESOLVED ACCUMULATOR. fold_accumulator_type can +// arrive as the container declaration's parametric shape -- Map with K and V the +// declaration's formals, bound to nothing at this call -- and the four shape tests above all +// read that as resolved (two children, neither unit-like). The init arm then wrote the formals +// straight into a turbofish, `v1_rt::rc_empty_map::()`, four sites on the 00_compile +// closure (v2.lens.unit_modeling) while the lambda beside it had already fallen back to `_`. +// The contextual method result type IS the resolved accumulator here, so a shape whose atoms are +// unbound in the closure scope is under-resolved exactly like an empty one. fn emit_rust_fold_method_call(method_call_node: Node, fold_accumulator_type: Node?, result_type: InferredNode?, receiver: Node, args: List, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { let recv_str = emit_typed_iter_owned_receiver(receiver: receiver, downstream: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) let elem_type_str = collection_element_type(receiver_type: receiver.inferred, shared_types: shared_types, source_indices: scope.type_env.source_indices, emit_info: emit_info, type_env: scope.type_env) @@ -10106,14 +10118,6 @@ fn emit_rust_fold_method_call(method_call_node: Node, fold_accumulator_type: Nod let is_under_resolved_list = node_is_element_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_set_collection(n: acc_type, source_indices: scope.type_env.source_indices) && acc_type.children |> count == 0 let is_under_resolved_set = node_is_set_collection(n: acc_type, source_indices: scope.type_env.source_indices) && (acc_type.children |> count == 0 || acc_children_have_unit) let is_under_resolved_non_collection = !node_is_keyed_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_element_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_collection(n: acc_type, source_indices: scope.type_env.source_indices) - // A DECLARATION'S OWN PARAMETER NAMES ARE NOT A RESOLVED ACCUMULATOR. fold_accumulator_type can - // arrive as the container declaration's parametric shape -- Map with K and V the - // declaration's formals, bound to nothing at this call -- and the four shape tests above all - // read that as resolved (two children, neither unit-like). The init arm then wrote the formals - // straight into a turbofish, `v1_rt::rc_empty_map::()`, four sites on the 00_compile - // closure (v2.lens.unit_modeling) while the lambda beside it had already fallen back to `_`. - // The contextual method result type IS the resolved accumulator here, so a shape whose atoms are - // unbound in the closure scope is under-resolved exactly like an empty one. let is_under_resolved_generic = type_node_has_closure_unbound_generic_atom(n: acc_type, generic_param_names: emit_info.fn_generic_param_names, env: scope.type_env, source_indices: scope.type_env.source_indices) if is_under_resolved_map || is_under_resolved_list || is_under_resolved_set || is_under_resolved_non_collection || is_under_resolved_generic { match contextual_acc_type { From 7f434917c619e0d5fbb02af290148aede2e4022b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 14:51:57 +0000 Subject: [PATCH 23/30] Regen round 1 (BuildBuddy invocation ebbdffc5, compiler gunbc=9830014a4e965ddb built from the committed mirror): v1_compiler_emit_rust.rs regenerated; candidate patch sha 05ce734c52890571 --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 816 +++++++++++++-------- 1 file changed, 517 insertions(+), 299 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 9dcd2f15425..8e912f6ecc4 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -64,7 +64,7 @@ pub use crate::v1_compiler_closure_stub_v2_std_text_rust::closure_stub_v2_std_te pub use crate::v1_compiler_coercion::decl_identity_file; pub use crate::v1_compiler_coercion::{ coerce_primitive_type, is_copy, lookup_checkpoint, rust_seed_host_numeric_alias, - type_reference_decl_file, + target_callable, type_reference_decl_file, }; pub use crate::v1_compiler_compiler_tests_rust::compiler_tests_source; use crate::v1_compiler_emit::BoundOperation::{ @@ -184,7 +184,7 @@ use crate::v1_std_core::CompilerDiagnostic::{ InternalError, ParameterDefaultFormNotAdmitted, ReferenceDerivedImportExportUnproven, ReferenceDerivedImportProviderUnknown, UnlistedImportUse, }; -use crate::v1_std_core::Connective::{Conj, Disj, NoConnective}; +use crate::v1_std_core::Connective::{Arrow, Conj, Disj, NoConnective}; use crate::v1_std_core::ExprData::{ ExprBinOp, ExprBlock, ExprCall, ExprCast, ExprError, ExprFieldAccess, ExprForEach, ExprIf, ExprIndex, ExprLambda, ExprLet, ExprListLit, ExprLiteral, ExprMatch, ExprMethodCall, @@ -319,6 +319,74 @@ pub fn render_rust_type( } } +pub fn rust_type_node_is_arrow(n: Rc) -> bool { + (n.connective.clone() == Connective::Arrow) +} + +pub fn render_rust_arrow_type( + n: Rc, + shared_types: Rc>, + source_indices: Rc>>, + emit_info: Rc, +) -> String { + { + let repr = crate::v1_compiler_coercion::target_callable(RenderTarget::Rust); + let param_strs = Rc::new({ + let mut __result = Vec::new(); + for p in n.params.clone().iter().cloned() { + __result.push(render_rust_type( + crate::v1_std_core::param_node_type_expr(p.clone()), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + )); + } + __result + }); + let param_str = param_strs.clone().join(&repr.param_separator.clone()); + let spec = crate::v1_compiler_emit_core_support::language_spec(RenderTarget::Rust); + 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(), + emit_info.clone(), + ), + _ => spec.void_type.clone(), + }; + match spec.callable_type_template.clone() { + Some(t) => v1_rt::replace( + v1_rt::replace(t.clone(), "{params}".to_string(), param_str.clone()), + "{return}".to_string(), + ret_str.clone(), + ), + None => { + if (ret_str.clone() == "".to_string()) { + v1_rt::replace( + v1_rt::replace( + repr.template.clone(), + v1_rt::concat(repr.return_separator.clone(), "{return}".to_string()), + "".to_string(), + ), + "{params}".to_string(), + param_str.clone(), + ) + } else { + v1_rt::replace( + v1_rt::replace( + repr.template.clone(), + "{params}".to_string(), + param_str.clone(), + ), + "{return}".to_string(), + ret_str.clone(), + ) + } + } + } + } +} + pub fn render_rust_type_without_applied_binding( n: Rc, shared_types: Rc>, @@ -342,121 +410,49 @@ pub fn render_rust_type_without_applied_binding( if is_host_diagnostics_carrier_type(n.clone(), source_indices.clone()) { return render_rust_diagnostics_carrier_applied(shared_types.clone()); } - if (((n.connective.clone() == Connective::NoConnective) - && ((n.children.clone().len() as i64) > 0)) - && !crate::std_types::is_container_type(crate::v1_std_core::authored_name_at( - source_indices.clone(), - n.clone(), - ))) - { - render_rust_applied_via_emit_info( + if rust_type_node_is_arrow(n.clone()) { + render_rust_arrow_type( n.clone(), shared_types.clone(), source_indices.clone(), emit_info.clone(), ) } else { - if crate::v1_compiler_infer_types::node_is_set_collection( - n.clone(), - source_indices.clone(), - ) { - match n.children.clone().first().cloned() { - Some(elem_child) => { - let elem_node = - crate::v1_compiler_infer_types::child_type_node(elem_child.clone()); - let elem_is_type_var = if (elem_node.inferred.clone() != None) { - is_type_variable(elem_node.inferred.clone().clone().unwrap()) - } else { - false - }; - if elem_is_type_var.clone() { - emit_rust_compile_error_expr("Set element type unresolved".to_string()) - } else { - if !rust_btree_set_element_ord_eligible( - elem_node.clone(), - source_indices.clone(), - emit_info.clone(), - ) { - { - let elem_name = crate::v1_std_core::authored_name_at( - source_indices.clone(), - elem_node.clone(), - ); - emit_rust_compile_error_expr(v1_rt::concat( - v1_rt::concat( - "Set element type ".to_string(), - elem_name.clone(), - ), - " is not Ord-eligible for BTreeSet".to_string(), - )) - } - } else { - crate::v1_compiler_emit::render_node_type( - n.clone(), - RenderTarget::Rust, - shared_types.clone(), - source_indices.clone(), - ) - } - } - } - None => emit_rust_compile_error_expr("Set missing element type".to_string()), + if ((((n.connective.clone() == Connective::NoConnective) + && ((n.children.clone().len() as i64) > 0)) + && !crate::std_types::is_container_type(crate::v1_std_core::authored_name_at( + source_indices.clone(), + n.clone(), + ))) + && closed_alias_peels_zero_param(emit_info.fn_type_env.clone(), n.clone())) + { + { + let leaf = crate::v1_std_core::qualified_last_segment( + crate::v1_std_core::authored_name_at(source_indices.clone(), n.clone()), + ); + render_rust_shared_type_with_optional( + n.clone(), + leaf.clone(), + leaf.clone(), + shared_types.clone(), + ) } } else { - if crate::v1_compiler_infer_types::node_is_keyed_collection( - n.clone(), - source_indices.clone(), - ) { - match n.children.clone().first().cloned() { - Some(key_child) => { - let key_node = - crate::v1_compiler_infer_types::child_type_node(key_child.clone()); - let val_node = - match n.children.clone().iter().cloned().skip(1 as usize).next() { - Some(val_child) => { - crate::v1_compiler_infer_types::child_type_node( - val_child.clone(), - ) - } - None => type_variable_node("map_value".to_string()), - }; - let key_str = render_rust_type( - key_node.clone(), - shared_types.clone(), - source_indices.clone(), - emit_info.clone(), - ); - let val_str = render_rust_type( - val_node.clone(), - shared_types.clone(), - source_indices.clone(), - emit_info.clone(), - ); - let tn = crate::v1_std_core::authored_name_at( - source_indices.clone(), - n.clone(), - ); - let base = crate::v1_compiler_emit::emit_map_type( - key_str.clone(), - val_str.clone(), - RenderTarget::Rust, - ); - render_rust_shared_type_with_optional( - n.clone(), - tn.clone(), - base.clone(), - shared_types.clone(), - ) - } - None => crate::v1_compiler_emit::render_node_type( - n.clone(), - RenderTarget::Rust, - shared_types.clone(), - source_indices.clone(), - ), - } + if (((n.connective.clone() == Connective::NoConnective) + && ((n.children.clone().len() as i64) > 0)) + && !crate::std_types::is_container_type(crate::v1_std_core::authored_name_at( + source_indices.clone(), + n.clone(), + ))) + { + render_rust_applied_via_emit_info( + n.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ) } else { - if crate::v1_compiler_infer_types::node_is_element_collection( + if crate::v1_compiler_infer_types::node_is_set_collection( n.clone(), source_indices.clone(), ) { @@ -465,60 +461,178 @@ pub fn render_rust_type_without_applied_binding( let elem_node = crate::v1_compiler_infer_types::child_type_node( elem_child.clone(), ); - let inner_str = render_rust_type( - elem_node.clone(), - shared_types.clone(), - source_indices.clone(), - emit_info.clone(), - ); - let tn = crate::v1_std_core::authored_name_at( - source_indices.clone(), + let elem_is_type_var = if (elem_node.inferred.clone() != None) { + is_type_variable(elem_node.inferred.clone().clone().unwrap()) + } else { + false + }; + if elem_is_type_var.clone() { + emit_rust_compile_error_expr( + "Set element type unresolved".to_string(), + ) + } else { + if !rust_btree_set_element_ord_eligible( + elem_node.clone(), + source_indices.clone(), + emit_info.clone(), + ) { + { + let elem_name = crate::v1_std_core::authored_name_at( + source_indices.clone(), + elem_node.clone(), + ); + emit_rust_compile_error_expr(v1_rt::concat( + v1_rt::concat( + "Set element type ".to_string(), + elem_name.clone(), + ), + " is not Ord-eligible for BTreeSet".to_string(), + )) + } + } else { + crate::v1_compiler_emit::render_node_type( + n.clone(), + RenderTarget::Rust, + shared_types.clone(), + source_indices.clone(), + ) + } + } + } + None => { + emit_rust_compile_error_expr("Set missing element type".to_string()) + } + } + } else { + if crate::v1_compiler_infer_types::node_is_keyed_collection( + n.clone(), + source_indices.clone(), + ) { + match n.children.clone().first().cloned() { + Some(key_child) => { + let key_node = crate::v1_compiler_infer_types::child_type_node( + key_child.clone(), + ); + let val_node = match n + .children + .clone() + .iter() + .cloned() + .skip(1 as usize) + .next() + { + Some(val_child) => { + crate::v1_compiler_infer_types::child_type_node( + val_child.clone(), + ) + } + None => type_variable_node("map_value".to_string()), + }; + let key_str = render_rust_type( + key_node.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ); + let val_str = render_rust_type( + val_node.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ); + let tn = crate::v1_std_core::authored_name_at( + source_indices.clone(), + n.clone(), + ); + let base = crate::v1_compiler_emit::emit_map_type( + key_str.clone(), + val_str.clone(), + RenderTarget::Rust, + ); + render_rust_shared_type_with_optional( + n.clone(), + tn.clone(), + base.clone(), + shared_types.clone(), + ) + } + None => crate::v1_compiler_emit::render_node_type( n.clone(), - ); - let base = crate::v1_compiler_emit::emit_container( - tn.clone(), - inner_str.clone(), RenderTarget::Rust, - ); - render_rust_shared_type_with_optional( - n.clone(), - tn.clone(), - base.clone(), shared_types.clone(), - ) + source_indices.clone(), + ), } - None => crate::v1_compiler_emit::render_node_type( - n.clone(), - RenderTarget::Rust, - shared_types.clone(), - source_indices.clone(), - ), - } - } else { - { - let tn = crate::v1_std_core::authored_name_at( - source_indices.clone(), - n.clone(), - ); - if type_node_has_unbound_type_variable( + } else { + if crate::v1_compiler_infer_types::node_is_element_collection( n.clone(), - emit_info.fn_generic_param_names.clone(), source_indices.clone(), ) { - "_".to_string() - } else { - if is_host_text_carrier_type(n.clone(), source_indices.clone()) { - rust_carrier_optional_wrap( - n.clone(), - render_rust_text_carrier(shared_types.clone()), - ) - } else { - crate::v1_compiler_emit::render_node_type( + match n.children.clone().first().cloned() { + Some(elem_child) => { + let elem_node = + crate::v1_compiler_infer_types::child_type_node( + elem_child.clone(), + ); + let inner_str = render_rust_type( + elem_node.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ); + let tn = crate::v1_std_core::authored_name_at( + source_indices.clone(), + n.clone(), + ); + let base = crate::v1_compiler_emit::emit_container( + tn.clone(), + inner_str.clone(), + RenderTarget::Rust, + ); + render_rust_shared_type_with_optional( + n.clone(), + tn.clone(), + base.clone(), + shared_types.clone(), + ) + } + None => crate::v1_compiler_emit::render_node_type( n.clone(), RenderTarget::Rust, shared_types.clone(), source_indices.clone(), - ) + ), + } + } else { + { + let tn = crate::v1_std_core::authored_name_at( + source_indices.clone(), + n.clone(), + ); + if type_node_has_unbound_type_variable( + n.clone(), + emit_info.fn_generic_param_names.clone(), + source_indices.clone(), + ) { + "_".to_string() + } else { + if is_host_text_carrier_type( + n.clone(), + source_indices.clone(), + ) { + rust_carrier_optional_wrap( + n.clone(), + render_rust_text_carrier(shared_types.clone()), + ) + } else { + crate::v1_compiler_emit::render_node_type( + n.clone(), + RenderTarget::Rust, + shared_types.clone(), + source_indices.clone(), + ) + } + } } } } @@ -1120,6 +1234,11 @@ pub fn rust_witness_carrier_from_type_node( source_indices: Rc>>, ) -> Option { { + if ((type_node.inferred.clone() != None) + && crate::v1_std_core::is_compiler_error(type_node.inferred.clone().clone().unwrap())) + { + return None; + } if type_node_has_unbound_type_variable( type_node.clone(), emit_info.fn_generic_param_names.clone(), @@ -2857,7 +2976,11 @@ pub fn render_rust_alias_rhs_type( n.clone(), shared_types.clone(), source_indices.clone(), - crate::v1_compiler_infer_emit_info::empty_emit_graph_info(), + crate::v1_compiler_infer_emit_info::emit_info_with_fn_type_context( + crate::v1_compiler_infer_emit_info::empty_emit_graph_info(), + generic_param_names.clone(), + scope.type_env.clone(), + ), ) } } @@ -8198,6 +8321,8 @@ pub fn reference_derived_use_line_plan( }); let type_surface_names = crate::v1_compiler_emit_core_support::unique_strings(item_emit_surface_names.clone()); + let qualified_surface_leaves = + qualified_type_surface_leaf_candidates(type_surface_names.clone(), registry.clone()); let field_surface_names = collect_items_field_import_surface_names( item_emit_surface_names.clone(), emit_info.clone(), @@ -8255,8 +8380,14 @@ pub fn reference_derived_use_line_plan( v1_rt::concat( v1_rt::concat( v1_rt::concat( - v1_rt::concat(unlisted_type_names.clone(), value_names.clone()), - type_surface_names.clone(), + v1_rt::concat( + v1_rt::concat( + unlisted_type_names.clone(), + value_names.clone(), + ), + type_surface_names.clone(), + ), + qualified_surface_leaves.clone(), ), field_surface_names.clone(), ), @@ -8450,6 +8581,52 @@ v1_rt::concat(block_lines.clone(), fallback.clone()) } } +pub fn qualified_type_surface_leaf_candidates( + names: Rc>, + registry: Rc>>, +) -> Rc> { + Rc::new({ + let mut __result = Vec::new(); + for name in names.iter().cloned() { + __result.extend( + (*if !v1_rt::string_contains(&name, ".".to_string()) { + Rc::new(vec![]) + } else { + { + let leaf = crate::v1_std_core::qualified_last_segment(name.clone()); + match v1_rt::map_get(®istry, name.clone()) { + Some(qualified_info) => { + if is_duplicate_qualified_item_registry_marker( + qualified_info.clone(), + ) { + Rc::new(vec![]) + } else { + match v1_rt::map_get(®istry, leaf.clone()) { + Some(bare_info) => { + if (bare_info.module_name.clone() + == qualified_info.module_name.clone()) + { + Rc::new(vec![leaf.clone()]) + } else { + Rc::new(vec![]) + } + } + None => Rc::new(vec![]), + } + } + } + None => Rc::new(vec![]), + } + } + }) + .iter() + .cloned(), + ); + } + __result + }) +} + pub fn reference_derived_use_lines( items: Rc>>, unlisted_type_names: Rc>, @@ -23179,12 +23356,22 @@ pub fn lambda_param_type_strs( ) { None } else { - Some(render_rust_type( - param_type.clone(), - shared_types.clone(), - source_indices.clone(), - emit_info.clone(), - )) + { + let rendered = render_rust_type( + param_type.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ); + if rust_fold_rendered_type_has_any_spurious_generic( + rendered.clone(), + emit_info.fn_generic_param_names.clone(), + ) { + None + } else { + Some(rendered.clone()) + } + } } } } @@ -23549,9 +23736,16 @@ pub fn emit_rust_fold_method_call( acc_type.clone(), scope.type_env.clone().source_indices.clone(), )); - if (((is_under_resolved_map.clone() || is_under_resolved_list.clone()) + let is_under_resolved_generic = type_node_has_closure_unbound_generic_atom( + acc_type.clone(), + emit_info.fn_generic_param_names.clone(), + scope.type_env.clone(), + scope.type_env.clone().source_indices.clone(), + ); + if ((((is_under_resolved_map.clone() || is_under_resolved_list.clone()) || is_under_resolved_set.clone()) || is_under_resolved_non_collection.clone()) + || is_under_resolved_generic.clone()) { match contextual_acc_type.clone() { Some(concrete_type) => concrete_type.clone(), @@ -24807,6 +25001,14 @@ pub fn emit_rust_generic_method_call( } } +pub fn rust_unrealized_service_op_refusal( + service_name: String, + method: String, + module_name: String, +) -> String { + v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat("panic!(\"unrealized host seam: service op ".to_string(), service_name.clone()), ".".to_string()), method.clone()), " in ".to_string()), module_name.clone()), ": the Rust realization binds a service only through an async fn parameter, and this function declares none\")".to_string()) +} + pub fn emit_typed_method_call( method_call_node: Rc, receiver: Rc, @@ -24827,152 +25029,168 @@ pub fn emit_typed_method_call( op_params, .. } => { - let var_name = - crate::v1_compiler_emit_core_support::service_var_name(svc_name.clone()); - let si = scope.type_env.clone().source_indices.clone(); - let filled_args = fill_op_default_args( - args.clone(), - op_params.clone(), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - ); - let optional_param_set = Rc::new({ - let mut __result = Vec::new(); - for p in op_params.iter().cloned() { - if (crate::v1_std_core::param_node_type_expr(p.clone()) - .return_cardinality - .clone() - == Cardinality::CardOptional) - { - __result.push(p); - } - } - __result - }) - .iter() - .cloned() - .fold( - v1_rt::rc_empty_map::(), - |acc: Rc>, p: Rc| { - v1_rt::rc_map_insert( - acc, - crate::v1_std_core::param_node_name_at(p.clone(), si.clone()), - true, - ) - }, - ); - let json_param_set = Rc::new({ - let mut __result = Vec::new(); - for p in op_params.iter().cloned() { - if (crate::v1_compiler_coercion::coerce_primitive_type( - RenderTarget::Rust, - crate::v1_std_core::authored_name_at( - si.clone(), - crate::v1_std_core::param_node_type_expr(p.clone()), - ), - crate::v1_compiler_coercion::type_reference_decl_file( - crate::v1_std_core::param_node_type_expr(p.clone()), - ), - ) == "serde_json::Value".to_string()) - { - __result.push(p); - } - } - __result - }) - .iter() - .cloned() - .fold( - v1_rt::rc_empty_map::(), - |acc: Rc>, p: Rc| { - v1_rt::rc_map_insert( - acc, - crate::v1_std_core::param_node_name_at(p.clone(), si.clone()), - true, - ) - }, - ); - let arg_strs = Rc::new({ - let mut __result = Vec::new(); - for a in filled_args.iter().cloned() { - __result.push({ - let arg_str = emit_typed_expr( - crate::v1_std_core::arg_value(a.clone()), - registry.clone(), - scope.clone(), - depth.clone(), - shared_types.clone(), - emit_info.clone(), - 1024, - ); - let aname = match crate::v1_std_core::arg_name_at(a.clone(), si.clone()) - { - Some(n) => n.clone(), - None => "".to_string(), - }; - let param_is_json = match v1_rt::map_get(&json_param_set, aname.clone()) - { - Some(_) => true, - None => false, - }; - let param_is_optional = - match v1_rt::map_get(&optional_param_set, aname.clone()) { - Some(_) => true, - None => false, - }; - let needs_optional = (param_is_optional.clone() - && (is_already_optional( - crate::v1_std_core::arg_value(a.clone()), - emit_info.clone(), - scope.clone(), - ) == false)); - let coerced = if (param_is_json.clone() - && is_string_typed_expr( - crate::v1_std_core::arg_value(a.clone()), - si.clone(), - )) { - v1_rt::concat( - v1_rt::concat( - "serde_json::from_str(&".to_string(), - arg_str.clone(), - ), - ").unwrap()".to_string(), + if !crate::v1_compiler_infer_service::is_typed_service_call_receiver( + receiver.clone(), + scope.type_env.clone().source_indices.clone(), + ) { + rust_unrealized_service_op_refusal( + svc_name.clone(), + method.clone(), + scope.module_name.clone(), + ) + } else { + { + let var_name = crate::v1_compiler_emit_core_support::service_var_name( + svc_name.clone(), + ); + let si = scope.type_env.clone().source_indices.clone(); + let filled_args = fill_op_default_args( + args.clone(), + op_params.clone(), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + ); + let optional_param_set = Rc::new({ + let mut __result = Vec::new(); + for p in op_params.iter().cloned() { + if (crate::v1_std_core::param_node_type_expr(p.clone()) + .return_cardinality + .clone() + == Cardinality::CardOptional) + { + __result.push(p); + } + } + __result + }) + .iter() + .cloned() + .fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, p: Rc| { + v1_rt::rc_map_insert( + acc, + crate::v1_std_core::param_node_name_at(p.clone(), si.clone()), + true, ) - } else { - arg_str.clone() - }; - if needs_optional.clone() { - v1_rt::concat( - v1_rt::concat("Some(".to_string(), coerced.clone()), - ")".to_string(), + }, + ); + let json_param_set = Rc::new({ + let mut __result = Vec::new(); + for p in op_params.iter().cloned() { + if (crate::v1_compiler_coercion::coerce_primitive_type( + RenderTarget::Rust, + crate::v1_std_core::authored_name_at( + si.clone(), + crate::v1_std_core::param_node_type_expr(p.clone()), + ), + crate::v1_compiler_coercion::type_reference_decl_file( + crate::v1_std_core::param_node_type_expr(p.clone()), + ), + ) == "serde_json::Value".to_string()) + { + __result.push(p); + } + } + __result + }) + .iter() + .cloned() + .fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, p: Rc| { + v1_rt::rc_map_insert( + acc, + crate::v1_std_core::param_node_name_at(p.clone(), si.clone()), + true, ) - } else { - coerced.clone() + }, + ); + let arg_strs = Rc::new({ + let mut __result = Vec::new(); + for a in filled_args.iter().cloned() { + __result.push({ + let arg_str = emit_typed_expr( + crate::v1_std_core::arg_value(a.clone()), + registry.clone(), + scope.clone(), + depth.clone(), + shared_types.clone(), + emit_info.clone(), + 1024, + ); + let aname = match crate::v1_std_core::arg_name_at( + a.clone(), + si.clone(), + ) { + Some(n) => n.clone(), + None => "".to_string(), + }; + let param_is_json = + match v1_rt::map_get(&json_param_set, aname.clone()) { + Some(_) => true, + None => false, + }; + let param_is_optional = + match v1_rt::map_get(&optional_param_set, aname.clone()) { + Some(_) => true, + None => false, + }; + let needs_optional = (param_is_optional.clone() + && (is_already_optional( + crate::v1_std_core::arg_value(a.clone()), + emit_info.clone(), + scope.clone(), + ) == false)); + let coerced = if (param_is_json.clone() + && is_string_typed_expr( + crate::v1_std_core::arg_value(a.clone()), + si.clone(), + )) { + v1_rt::concat( + v1_rt::concat( + "serde_json::from_str(&".to_string(), + arg_str.clone(), + ), + ").unwrap()".to_string(), + ) + } else { + arg_str.clone() + }; + if needs_optional.clone() { + v1_rt::concat( + v1_rt::concat("Some(".to_string(), coerced.clone()), + ")".to_string(), + ) + } else { + coerced.clone() + } + }); } + __result }); - } - __result - }); - let args_str = arg_strs.clone().join(&", ".to_string()); - v1_rt::concat( - v1_rt::concat( + let args_str = arg_strs.clone().join(&", ".to_string()); v1_rt::concat( v1_rt::concat( - v1_rt::concat(var_name.clone(), ".".to_string()), - crate::v1_compiler_emit::emit_ident( - method.clone(), - RenderTarget::Rust, + v1_rt::concat( + v1_rt::concat( + v1_rt::concat(var_name.clone(), ".".to_string()), + crate::v1_compiler_emit::emit_ident( + method.clone(), + RenderTarget::Rust, + ), + ), + "(".to_string(), ), + args_str.clone(), ), - "(".to_string(), - ), - args_str.clone(), - ), - ").await?".to_string(), - ) + ").await?".to_string(), + ) + } + } } MethodSemantics::AlgebraMethodSemantics { method_def, From e9900e26fe4f5033c5fb899ddb49ea55dfba0b96 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 15:07:18 +0000 Subject: [PATCH 24/30] Regen round 2 (BuildBuddy, compiler gunbc=75d74698aebcdb6e built from installed ce959e40604ffdd5): std_algebra.rs, std_nat.rs -- arrow returns now render through the Rust renderer (Rc> for List, Nat preserved); candidate patch sha b5b409aeebbeb6c4 --- src/v1/stage0/src/std_algebra.rs | 4 ++-- src/v1/stage0/src/std_nat.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/v1/stage0/src/std_algebra.rs b/src/v1/stage0/src/std_algebra.rs index a2b8c0e1f4c..03c8a17ad5e 100644 --- a/src/v1/stage0/src/std_algebra.rs +++ b/src/v1/stage0/src/std_algebra.rs @@ -281,8 +281,8 @@ pub struct FinitelySupportedFunction { pub insert: Rc Rc>>, pub merge: Rc>) -> Rc>>, - pub map_keys: Rc Rc>>, - pub map_values: Rc Rc>>, + pub map_keys: Rc Rc>>, + pub map_values: Rc Rc>>, pub map_has: Rc bool>, pub contains_key: Rc bool>, pub size: Rc i64>, diff --git a/src/v1/stage0/src/std_nat.rs b/src/v1/stage0/src/std_nat.rs index 19188c278f1..796b083f66c 100644 --- a/src/v1/stage0/src/std_nat.rs +++ b/src/v1/stage0/src/std_nat.rs @@ -42,11 +42,11 @@ pub fn nat_min(a: Nat, b: Nat) -> Nat { } } -pub fn nat_range_inclusive(lo: Nat, hi: Nat) -> Rc> { +pub fn nat_range_inclusive(lo: Nat, hi: Nat) -> Rc> { nat_range_accumulate(lo.clone(), hi.clone(), Rc::new(vec![])) } -pub fn nat_range_accumulate(mut lo: Nat, mut hi: Nat, mut acc: Rc>) -> Rc> { +pub fn nat_range_accumulate(mut lo: Nat, mut hi: Nat, mut acc: Rc>) -> Rc> { loop { if (lo.clone() > hi.clone()) { break acc; From 675d7ce78bad98139ab1dbb87be27ed538a61b84 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 15:54:42 +0000 Subject: [PATCH 25/30] Arrow positions deviate from the generic renderer only for the two defect shapes: the unconditioned route emitted 2790 refusals where 15 stood; fix the arrow probe's variant spelling --- ...d_call_target_realization_witness_test.dag | 2 +- src/v1/05_emit_rust.dag | 32 +++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index cc462a5376e..f2a52bdcc57 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -320,7 +320,7 @@ test fn w_zero_param_alias_in_an_arrow_return_renders_without_its_rhs_arguments( // honours the binding and must be what an arrow's positions render through. test fn w_arrow_return_type_keeps_its_applied_binding() -> Bool { compile_dag_rust_emit_check( - "module test.claim.arrow_binding_probe\nimport std.types { Int, String }\nimport v2.std.diagnostic { Outcome }\ntype Box2 { v: T }\nfn probe() -> fn(Int) -> Outcome> { fn(n) { Outcome::Accepted { value: Box2 { v: \"x\" } } } }\n", + "module test.claim.arrow_binding_probe\nimport std.types { Int, String }\nimport v2.std.diagnostic { Outcome, Accepted }\ntype Box2 { v: T }\nfn probe() -> fn(Int) -> Outcome> { fn(n) { Accepted { value: Box2 { v: \"x\" } } } }\n", "src/test_claim_arrow_binding_probe.rs", ["Box2"], ["Rc>"] diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 7d529fff27b..29d923c6ac8 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -233,6 +233,34 @@ fn render_rust_type(n: Node, shared_types: Set, source_indices: Map Rc>>>` -- the inner binding dropped (E0107 missing // generics for struct `Medium`, v2.compiler.compile stage_translate). The callable template and the // void arm are the same rows render_node_type consumes; only the per-position renderer changes. +// AN ARROW POSITION DEVIATES FROM THE TARGET-GENERIC RENDERER ONLY FOR THE TWO SHAPES THAT RENDERER +// CANNOT SPELL, AND THIS GATE IS MEASURED, NOT ASSUMED. The first cut routed EVERY arrow position +// through render_rust_type, and the regenerated seed then emitted 2790 rustc refusals on the +// 00_compile closure where the committed bytes had 15: the Rust renderer realizes a v2-declared +// Symbol/String structurally (Rc>, E0308 by the hundreds) and renders an out-of-scope +// type variable as `_` (E0121 inside fn signatures) -- spellings the generic renderer had been +// supplying at those positions, and which nothing in this change set out to alter. So a position +// takes the Rust renderer only when its subtree carries an applied-type binding the generic +// renderer would drop (the `Rc` E0107 class) or is itself a zero-parameter alias carrying +// its right-hand side's children (the `CompileLensOutcome<..>` E0107 class); every other position +// renders exactly as before this change. The deviation set is therefore the defect set. +fn render_rust_arrow_position(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { + let is_bare_zero_param_alias = n.connective == NoConnective && n.children |> count > 0 && closed_alias_peels_zero_param(env: emit_info.fn_type_env, n: n) + if type_node_carries_applied_binding(n: n, source_indices: source_indices) || is_bare_zero_param_alias { + render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + } else { + render_node_type(n: n, target: Rust, shared_types: shared_types, source_indices: source_indices) + } +} + +fn type_node_carries_applied_binding(n: Node, source_indices: Map) -> Bool { + let own = match find_property(props: n.properties, prop_name: "__applied_type_args", source_indices: source_indices) { + Present { value: applied } => applied.children |> count > 0 + Absent => false + } + own || n.children |> any(c => type_node_carries_applied_binding(n: child_type_node(ch: c), source_indices: source_indices)) +} + // Named rather than inlined because `if x == Variant {` parses as a record literal in .dag. fn rust_type_node_is_arrow(n: Node) -> Bool { n.connective == Arrow @@ -240,11 +268,11 @@ fn rust_type_node_is_arrow(n: Node) -> Bool { fn render_rust_arrow_type(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { let repr = target_callable(target: Rust) - let param_strs = n.params |> map(p => render_rust_type(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices, emit_info: emit_info)) + let param_strs = n.params |> map(p => render_rust_arrow_position(n: param_node_type_expr(n: p), shared_types: shared_types, source_indices: source_indices, emit_info: emit_info)) let param_str = param_strs |> join(separator: repr.param_separator) let spec = language_spec(target: Rust) let ret_str = match n.inferred { - Present { value: Resolved { node: rt } } => render_rust_type(n: rt, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) + Present { value: Resolved { node: rt } } => render_rust_arrow_position(n: rt, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) _ => spec.void_type } match spec.callable_type_template { From 077318463ebd3c05f583b51ba564461cc3ee3ddd Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 16:10:30 +0000 Subject: [PATCH 26/30] B: the init turbofish declines a declaration's own formals by the lambda's admission; F: a qualified type reference earns its use-line from the qualifier under export proof; both earlier cuts were measured non-events and are deleted --- ...d_call_target_realization_witness_test.dag | 11 +-- src/v1/05_emit_rust.dag | 70 +++++++++++-------- 2 files changed, 46 insertions(+), 35 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index f2a52bdcc57..a5f78c03c3d 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -278,11 +278,14 @@ test fn w_witness_carrier_falls_back_to_the_fn_return_when_the_value_identity_is // FOLD ACCUMULATOR, THE DISCRIMINATING RED. A fold whose init is empty_map() took the Map // declaration's own formals as its accumulator and wrote them into the turbofish: -// `v1_rt::rc_empty_map::()`. The fn's declared Map return is the resolved -// accumulator and must be what the init renders from. +// `v1_rt::rc_empty_map::()`. THE PROBE IMPORTS NOTHING ON PURPOSE: it mirrors +// v2.lens.unit_modeling, which resolves Map, Symbol, empty_map and map_insert by namespace alone -- +// under an explicit `import std.types { Map }` the accumulator resolves to the kernel container and +// the defect never fires (measured: that probe emitted `rc_empty_map::` on the +// defective compiler). The init must decline the formals exactly as the lambda beside it does. test fn w_fold_empty_map_init_renders_the_resolved_accumulator_not_the_declaration_formals() -> Bool { compile_dag_rust_emit_check( - "module test.claim.fold_accumulator_probe\nimport std.types { Int, String, Map }\nimport v2.std.node { Symbol }\nimport v2.std.collection { empty_map, map_insert }\ntype Row { field: Symbol, carrier: Symbol }\nfn rows() -> List { [Row { field: ^a, carrier: ^b }] }\nfn probe() -> Map { fold(rows(), init: empty_map(), f: fn(acc, row) { map_insert(m: acc, key: row.field, value: row.carrier) }) }\n", + "module test.claim.fold_accumulator_probe\n\ntype Row {\n field: Symbol\n carrier: Symbol\n}\n\ndata rows: List = [\n Row { field: ^a, carrier: ^b }\n]\n\nfn probe() -> Map {\n fold(rows, init: empty_map(), f: fn(acc, row) {\n map_insert(m: acc, key: row.field, value: row.carrier)\n })\n}\n", "src/test_claim_fold_accumulator_probe.rs", ["rc_empty_map::<"], ["rc_empty_map::"] @@ -335,7 +338,7 @@ test fn w_qualified_type_reference_earns_the_leaf_use_line() -> Bool { compile_dag_rust_emit_check( "module test.claim.qualified_type_ref_probe\nimport std.types { String }\ntype Fact { signature: String, classification: std.determinism.Determinism }\nfn probe(f: Fact) -> std.determinism.Determinism { f.classification }\n", "src/test_claim_qualified_type_ref_probe.rs", - ["use crate::std_determinism::Determinism"], + ["use crate::std_determinism::Determinism;"], ["std.determinism.Determinism"] ) } diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 29d923c6ac8..6dcc0945adc 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -4182,7 +4182,6 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< let value_names = unique_strings(items: items |> flat_map(item => collect_value_ref_names(n: item, source_indices: source_indices, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum))) let item_emit_surface_names = items |> flat_map(item => collect_item_emit_surface_names(item: item, source_indices: source_indices, emit_info: emit_info)) let type_surface_names = unique_strings(items: item_emit_surface_names) - let qualified_surface_leaves = qualified_type_surface_leaf_candidates(names: type_surface_names, registry: registry) let field_surface_names = collect_items_field_import_surface_names(surface_names: item_emit_surface_names, emit_info: emit_info) let variant_payload_structs = expand_variant_payload_struct_imports(names: type_surface_names, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum) let emitter_attested_anon_heads = unique_strings(items: items |> flat_map(item => collect_anonymous_record_lit_heads(n: item, source_indices: source_indices, type_summaries: emit_info.type_summaries))) @@ -4190,7 +4189,7 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< let emitted_source_tokens = rust_identifier_tokens(s: emitted_source) let emitted_source_token_set = emitted_source_tokens |> fold(init: empty_map(), f: (acc, t) => map_insert(acc, t, true)) - let candidates = unique_strings(items: concat(concat(concat(concat(concat(concat(unlisted_type_names, value_names), type_surface_names), qualified_surface_leaves), field_surface_names), variant_payload_structs), realized_surface_names)) + let candidates = unique_strings(items: concat(concat(concat(concat(concat(unlisted_type_names, value_names), type_surface_names), field_surface_names), variant_payload_structs), realized_surface_names)) |> filter(name => reference_derived_candidate_authored(module_source: module_source, name: name, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum) || emitter_attested_anon_heads |> any(h => h == name) @@ -4245,7 +4244,9 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< ) concat(block_lines, fallback) ) - ReferenceDerivedUseLinePlan { lines: lines, rows: rows } + let names_already_in_lines = lines |> flat_map(l => imported_names_in_use_line(line: l)) + let qualified_lines = qualified_type_reference_use_lines(names: type_surface_names, this_module_name: this_module_name, already: already, names_already_in_lines: names_already_in_lines, registry: registry, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) + ReferenceDerivedUseLinePlan { lines: concat(lines, qualified_lines), rows: rows } } } @@ -4254,26 +4255,28 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< // the surface walk collects the DOTTED spelling -- which is never an identifier token in the emitted // source, so the candidate filter dropped it before any disposition was assigned and the module // referenced a name it never imported (E0425 cannot find type `Determinism`, v2.std.determinism, -// two sites). The leaf is admitted as a candidate only when the qualified registry row resolves it -// AND the bare row names the SAME declaring module: the downstream lookups are bare-keyed and -// last-write-wins, and a leaf whose bare row points elsewhere would import a homonym from the wrong -// provider. That disagreement stays a loud unresolved name rather than a fabricated use-line. -fn qualified_type_surface_leaf_candidates(names: List, registry: Map) -> List { - names |> flat_map(name => +// two sites). The qualifier IS the provider the author named, so the line is synthesized from it +// directly -- under the same construction wall every other synthesized use-line passes: +// provider_proven_exports_symbol must hold for the leaf on that module, or nothing is emitted and +// the name stays a loud unresolved symbol. A first cut keyed this on the qualified item-registry +// overlay instead; that overlay carries no row for the reference and the cut was a measured +// NON-EVENT (falsifier m12 reddened nothing; the two sites stayed), so it is replaced, not kept. +fn qualified_type_reference_use_lines(names: List, this_module_name: String, already: Map, names_already_in_lines: List, registry: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { + let leaves_done = names_already_in_lines |> fold(init: empty_map(), f: (acc, nm) => map_insert(acc, nm, true)) + unique_strings(items: names |> flat_map(name => if !string_contains(s: name, pattern: ".") { [] } else { let leaf = qualified_last_segment(name: name) - match map_get(registry, name) { - Present { value: qualified_info } => - if is_duplicate_qualified_item_registry_marker(info: qualified_info) { [] } else { - match map_get(registry, leaf) { - Present { value: bare_info } => if bare_info.module_name == qualified_info.module_name { [leaf] } else { [] } - Absent => [] - } - } - Absent => [] + let segments = name |> split(delimiter: ".") + let qualifier = segments |> take(n: (segments |> count) - 1) |> join(separator: ".") + if qualifier == this_module_name || emit_map_has(m: already, key: leaf) || emit_map_has(m: leaves_done, key: leaf) || is_kernel_type(name: leaf) { + [] + } else if provider_proven_exports_symbol(name: leaf, provider_module: qualifier, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { + [concat(rust_visibility_prefix(), "use crate::", module_to_filename(name: qualifier), "::", emit_import_name(n: leaf, registry: registry), ";")] + } else { + [] } } - ) + )) } fn reference_derived_use_lines(items: List, unlisted_type_names: List, this_module_name: String, registry: Map, emit_info: EmitGraphInfo, local_type_names: List, already_imported_names: List, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, shared_types: Set, emitted_source: String) -> List { @@ -10123,15 +10126,19 @@ fn emit_typed_fold_lambda(lambda_expr: Node, acc_type_str: String, elem_type_str // instead would restate it, and would then have to be kept in step with any future change to the strip // -- reintroducing the shape of this defect while fixing this instance of it. `_` is also the device // already used for elem_render_has_spurious_generic a few bindings earlier. -// THE UNDER-RESOLVED-GENERIC ACCUMULATOR ARM (is_under_resolved_generic below): -// A DECLARATION'S OWN PARAMETER NAMES ARE NOT A RESOLVED ACCUMULATOR. fold_accumulator_type can -// arrive as the container declaration's parametric shape -- Map with K and V the -// declaration's formals, bound to nothing at this call -- and the four shape tests above all -// read that as resolved (two children, neither unit-like). The init arm then wrote the formals -// straight into a turbofish, `v1_rt::rc_empty_map::()`, four sites on the 00_compile -// closure (v2.lens.unit_modeling) while the lambda beside it had already fallen back to `_`. -// The contextual method result type IS the resolved accumulator here, so a shape whose atoms are -// unbound in the closure scope is under-resolved exactly like an empty one. +// THE INIT TURBOFISH DECLINES A DECLARATION'S OWN FORMALS, BY THE SAME ADMISSION THE LAMBDA USES. +// In a module that resolves Map, Symbol, empty_map and map_insert by namespace alone +// (v2.lens.unit_modeling imports none of them), the fold's accumulator arrives as the v2 Map +// declaration's parametric shape -- Map with K and V the declaration's formals -- and so +// does the call's contextual result type, so no choice between the two helps. The lambda beside +// the init already renders such an accumulator as `_` (rust_fold_rendered_type_has_any_spurious_generic +// over the rendered string), while the init arm wrote the formals into a turbofish: +// `v1_rt::rc_empty_map::()`, four sites on the 00_compile closure. The init now asks the same +// rendered-string admission and, where the formals are unbound in this fn's generic scope, defers +// the key and value types to the target's own inference exactly as the lambda does -- rustc binds +// them from the fold body or refuses loudly. An earlier cut of this repair instead widened the +// "under-resolved accumulator" test to prefer the contextual type; that was a measured NON-EVENT +// (falsifier m09: removing it reddened nothing, and the four sites stayed) and is deleted. fn emit_rust_fold_method_call(method_call_node: Node, fold_accumulator_type: Node?, result_type: InferredNode?, receiver: Node, args: List, registry: Map, scope: InferScope, depth: Int, shared_types: Set, emit_info: EmitGraphInfo) -> String { let recv_str = emit_typed_iter_owned_receiver(receiver: receiver, downstream: args, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info) let elem_type_str = collection_element_type(receiver_type: receiver.inferred, shared_types: shared_types, source_indices: scope.type_env.source_indices, emit_info: emit_info, type_env: scope.type_env) @@ -10146,8 +10153,7 @@ fn emit_rust_fold_method_call(method_call_node: Node, fold_accumulator_type: Nod let is_under_resolved_list = node_is_element_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_set_collection(n: acc_type, source_indices: scope.type_env.source_indices) && acc_type.children |> count == 0 let is_under_resolved_set = node_is_set_collection(n: acc_type, source_indices: scope.type_env.source_indices) && (acc_type.children |> count == 0 || acc_children_have_unit) let is_under_resolved_non_collection = !node_is_keyed_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_element_collection(n: acc_type, source_indices: scope.type_env.source_indices) && !node_is_collection(n: acc_type, source_indices: scope.type_env.source_indices) - let is_under_resolved_generic = type_node_has_closure_unbound_generic_atom(n: acc_type, generic_param_names: emit_info.fn_generic_param_names, env: scope.type_env, source_indices: scope.type_env.source_indices) - if is_under_resolved_map || is_under_resolved_list || is_under_resolved_set || is_under_resolved_non_collection || is_under_resolved_generic { + if is_under_resolved_map || is_under_resolved_list || is_under_resolved_set || is_under_resolved_non_collection { match contextual_acc_type { Present { value: concrete_type } => concrete_type Absent => acc_type @@ -10263,7 +10269,9 @@ fn emit_rust_fold_method_call(method_call_node: Node, fold_accumulator_type: Nod let init_func = expr_call_func_at(texpr: arg_value(n: init_arg), source_indices: scope.type_env.source_indices) if init_func == "empty_map" && acc_type_str != "_" && acc_type_str != "" && !acc_has_unit_child { let kv_type_str = rust_empty_map_kv_type_str(map_type: acc_type_node, shared_types: shared_types, source_indices: scope.type_env.source_indices) - if kv_type_str != "" { + if kv_type_str != "" && rust_fold_rendered_type_has_any_spurious_generic(type_str: concat("<", kv_type_str, ">"), generic_param_names: emit_info.fn_generic_param_names) { + "v1_rt::rc_empty_map::<_, _>()" + } else if kv_type_str != "" { concat("v1_rt::rc_empty_map::<", kv_type_str, ">()") } else { rust_shared_wrap_ctor(inner_expr: "HashMap::new() /* BRIDGE: fold empty_map value type unresolved */") From a5120f16b74fdcaf72c7357b0d74446bb0991c61 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 17:16:02 +0000 Subject: [PATCH 27/30] Regenerate the stage0 mirror at the 0773184 freeze: byte fixed point at round 3, three paths, each explained by an authority change srv1 (/tmp/xl0e.sh -> /tmp/xl0j.log), criterion = every regen-population file byte-equal to installed; full workspace rebuilt as the gate each round. round 1 gunbc=1dc61ba198c6750b from installed 0479b0df9fc5598e -> v1_compiler_emit_rust.rs round 2 gunbc=909aa212f353bd03 from installed 8ebedc7445fadbaa -> std_algebra.rs, v1_compiler_trait_derive_emit.rs round 3 gunbc=0d0cd70ec5b20db9 from installed 8713cb43f8ad848c -> BYTE FIXED POINT v1_compiler_emit_rust.rs <- 05_emit_rust.dag (gated arrow position, init turbofish admission, qualified-type use-lines) std_algebra.rs <- the gated arrow route restores the pre-e9900e2 spelling of the two arrow-typed fields v1_compiler_trait_derive_emit.rs <- one use-line synthesized for a qualified std.types.List reference under export proof Final installed tree 8713cb43f8ad848c. No hand edit to any generated file. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- src/v1/stage0/src/std_algebra.rs | 4 +- src/v1/stage0/src/v1_compiler_emit_rust.rs | 205 ++++++++++++------ .../src/v1_compiler_trait_derive_emit.rs | 1 + 3 files changed, 142 insertions(+), 68 deletions(-) diff --git a/src/v1/stage0/src/std_algebra.rs b/src/v1/stage0/src/std_algebra.rs index 03c8a17ad5e..a2b8c0e1f4c 100644 --- a/src/v1/stage0/src/std_algebra.rs +++ b/src/v1/stage0/src/std_algebra.rs @@ -281,8 +281,8 @@ pub struct FinitelySupportedFunction { pub insert: Rc Rc>>, pub merge: Rc>) -> Rc>>, - pub map_keys: Rc Rc>>, - pub map_values: Rc Rc>>, + pub map_keys: Rc Rc>>, + pub map_values: Rc Rc>>, pub map_has: Rc bool>, pub contains_key: Rc bool>, pub size: Rc i64>, diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 8e912f6ecc4..9f85f01ae36 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -319,6 +319,65 @@ pub fn render_rust_type( } } +pub fn render_rust_arrow_position( + n: Rc, + shared_types: Rc>, + source_indices: Rc>>, + emit_info: Rc, +) -> String { + { + let is_bare_zero_param_alias = (((n.connective.clone() == Connective::NoConnective) + && ((n.children.clone().len() as i64) > 0)) + && closed_alias_peels_zero_param(emit_info.fn_type_env.clone(), n.clone())); + if (type_node_carries_applied_binding(n.clone(), source_indices.clone()) + || is_bare_zero_param_alias.clone()) + { + render_rust_type( + n.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.clone(), + ) + } else { + crate::v1_compiler_emit::render_node_type( + n.clone(), + RenderTarget::Rust, + shared_types.clone(), + source_indices.clone(), + ) + } + } +} + +pub fn type_node_carries_applied_binding( + n: Rc, + source_indices: Rc>>, +) -> bool { + stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { + let own = match crate::v1_std_core::find_property( + n.properties.clone(), + "__applied_type_args".to_string(), + source_indices.clone(), + ) { + Some(applied) => ((applied.children.clone().len() as i64) > 0), + None => false, + }; + (own.clone() || { + let mut __found = false; + for c in n.children.clone().iter().cloned() { + if type_node_carries_applied_binding( + crate::v1_compiler_infer_types::child_type_node(c.clone()), + source_indices.clone(), + ) { + __found = true; + break; + } + } + __found + }) + }) +} + pub fn rust_type_node_is_arrow(n: Rc) -> bool { (n.connective.clone() == Connective::Arrow) } @@ -334,7 +393,7 @@ pub fn render_rust_arrow_type( let param_strs = Rc::new({ let mut __result = Vec::new(); for p in n.params.clone().iter().cloned() { - __result.push(render_rust_type( + __result.push(render_rust_arrow_position( crate::v1_std_core::param_node_type_expr(p.clone()), shared_types.clone(), source_indices.clone(), @@ -346,7 +405,7 @@ pub fn render_rust_arrow_type( let param_str = param_strs.clone().join(&repr.param_separator.clone()); let spec = crate::v1_compiler_emit_core_support::language_spec(RenderTarget::Rust); let ret_str = match n.inferred.clone().as_deref().cloned() { - Some(InferredNode::Resolved { node: rt, .. }) => render_rust_type( + Some(InferredNode::Resolved { node: rt, .. }) => render_rust_arrow_position( rt.clone(), shared_types.clone(), source_indices.clone(), @@ -8321,8 +8380,6 @@ pub fn reference_derived_use_line_plan( }); let type_surface_names = crate::v1_compiler_emit_core_support::unique_strings(item_emit_surface_names.clone()); - let qualified_surface_leaves = - qualified_type_surface_leaf_candidates(type_surface_names.clone(), registry.clone()); let field_surface_names = collect_items_field_import_surface_names( item_emit_surface_names.clone(), emit_info.clone(), @@ -8380,14 +8437,8 @@ pub fn reference_derived_use_line_plan( v1_rt::concat( v1_rt::concat( v1_rt::concat( - v1_rt::concat( - v1_rt::concat( - unlisted_type_names.clone(), - value_names.clone(), - ), - type_surface_names.clone(), - ), - qualified_surface_leaves.clone(), + v1_rt::concat(unlisted_type_names.clone(), value_names.clone()), + type_surface_names.clone(), ), field_surface_names.clone(), ), @@ -8574,57 +8625,74 @@ v1_rt::concat(block_lines.clone(), fallback.clone()) } __result }); + let names_already_in_lines = Rc::new({ + let mut __result = Vec::new(); + for l in lines.iter().cloned() { + __result.extend((*imported_names_in_use_line(l.clone())).iter().cloned()); + } + __result + }); + let qualified_lines = qualified_type_reference_use_lines( + type_surface_names.clone(), + this_module_name.clone(), + already.clone(), + names_already_in_lines.clone(), + registry.clone(), + export_sets.clone(), + typed_modules.clone(), + source_indices.clone(), + module_index.clone(), + ); Rc::new(ReferenceDerivedUseLinePlan { - lines: lines.clone(), + lines: v1_rt::concat(lines.clone(), qualified_lines.clone()), rows: rows.clone(), }) } } -pub fn qualified_type_surface_leaf_candidates( +pub fn qualified_type_reference_use_lines( names: Rc>, + this_module_name: String, + already: Rc>, + names_already_in_lines: Rc>, registry: Rc>>, + export_sets: Rc>>>, + typed_modules: Rc>>, + source_indices: Rc>>, + module_index: Rc, ) -> Rc> { - Rc::new({ - let mut __result = Vec::new(); - for name in names.iter().cloned() { - __result.extend( - (*if !v1_rt::string_contains(&name, ".".to_string()) { + { + let leaves_done = names_already_in_lines.iter().cloned().fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, nm: String| { + v1_rt::rc_map_insert(acc, nm.clone(), true) + }, + ); + crate::v1_compiler_emit_core_support::unique_strings(Rc::new({ + let mut __result = Vec::new(); + for name in names.iter().cloned() { + __result.extend((*if !v1_rt::string_contains(&name, ".".to_string()) { + Rc::new(vec![]) + } else { + { + let leaf = crate::v1_std_core::qualified_last_segment(name.clone()); +let segments = Rc::new(name.clone().split(&".".to_string()).map(|s| s.to_string()).collect::>()); +let qualifier = Rc::new(segments.clone().iter().cloned().take(((segments.clone().len() as i64) - 1) as usize).collect::>()).join(&".".to_string()); +if ((((qualifier.clone() == this_module_name.clone()) || crate::v1_compiler_infer_types::emit_map_has(already.clone(), leaf.clone())) || crate::v1_compiler_infer_types::emit_map_has(leaves_done.clone(), leaf.clone())) || crate::std_types::is_kernel_type(leaf.clone())) { Rc::new(vec![]) } else { - { - let leaf = crate::v1_std_core::qualified_last_segment(name.clone()); - match v1_rt::map_get(®istry, name.clone()) { - Some(qualified_info) => { - if is_duplicate_qualified_item_registry_marker( - qualified_info.clone(), - ) { - Rc::new(vec![]) - } else { - match v1_rt::map_get(®istry, leaf.clone()) { - Some(bare_info) => { - if (bare_info.module_name.clone() - == qualified_info.module_name.clone()) - { - Rc::new(vec![leaf.clone()]) - } else { - Rc::new(vec![]) - } - } - None => Rc::new(vec![]), - } - } - } - None => Rc::new(vec![]), - } + if provider_proven_exports_symbol(leaf.clone(), qualifier.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone()) { + Rc::new(vec![v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(rust_visibility_prefix(), "use crate::".to_string()), crate::v1_compiler_emit_core_support::module_to_filename(qualifier.clone())), "::".to_string()), emit_import_name(leaf.clone(), registry.clone())), ";".to_string())]) + } else { + Rc::new(vec![]) } - }) - .iter() - .cloned(), - ); - } - __result - }) + } +} + }).iter().cloned()); + } + __result + })) + } } pub fn reference_derived_use_lines( @@ -23736,16 +23804,9 @@ pub fn emit_rust_fold_method_call( acc_type.clone(), scope.type_env.clone().source_indices.clone(), )); - let is_under_resolved_generic = type_node_has_closure_unbound_generic_atom( - acc_type.clone(), - emit_info.fn_generic_param_names.clone(), - scope.type_env.clone(), - scope.type_env.clone().source_indices.clone(), - ); - if ((((is_under_resolved_map.clone() || is_under_resolved_list.clone()) + if (((is_under_resolved_map.clone() || is_under_resolved_list.clone()) || is_under_resolved_set.clone()) || is_under_resolved_non_collection.clone()) - || is_under_resolved_generic.clone()) { match contextual_acc_type.clone() { Some(concrete_type) => concrete_type.clone(), @@ -24012,16 +24073,28 @@ pub fn emit_rust_fold_method_call( shared_types.clone(), scope.type_env.clone().source_indices.clone(), ); - if (kv_type_str.clone() != "".to_string()) { - v1_rt::concat( + if ((kv_type_str.clone() != "".to_string()) + && rust_fold_rendered_type_has_any_spurious_generic( v1_rt::concat( - "v1_rt::rc_empty_map::<".to_string(), - kv_type_str.clone(), + v1_rt::concat("<".to_string(), kv_type_str.clone()), + ">".to_string(), ), - ">()".to_string(), - ) + emit_info.fn_generic_param_names.clone(), + )) + { + "v1_rt::rc_empty_map::<_, _>()".to_string() } else { - rust_shared_wrap_ctor("HashMap::new() /* BRIDGE: fold empty_map value type unresolved */".to_string()) + if (kv_type_str.clone() != "".to_string()) { + v1_rt::concat( + v1_rt::concat( + "v1_rt::rc_empty_map::<".to_string(), + kv_type_str.clone(), + ), + ">()".to_string(), + ) + } else { + rust_shared_wrap_ctor("HashMap::new() /* BRIDGE: fold empty_map value type unresolved */".to_string()) + } } } } else { diff --git a/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs b/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs index cec8ebda4e1..9427918702f 100644 --- a/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs +++ b/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs @@ -37,6 +37,7 @@ pub use crate::std_trait_derive_shape::{ repr_grounding_derive_completeness_predicate, repr_grounding_group_completion_carrier, repr_grounding_supplemental_bool_host_bridge_target, }; +pub use crate::std_types::List; pub use crate::std_types::{container_template_algebra, is_container_type}; pub use crate::v1_compiler_artifact::RenderTarget; use crate::v1_compiler_artifact::RenderTarget::Rust; From b0e4ad377634a4f08f9389ae6b9e784ed0223716 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 19:52:16 +0000 Subject: [PATCH 28/30] One renderer for every arrow position; a type position never takes the variant arm; the qualified route synthesizes use-lines only for types the emitted source names Four regressions the 0773184 fixed point put on the closure, each with its discriminating row: - E0603 x16: the qualified-type route synthesized `pub use crate::v2_std_nat::Succ;` for every `v2.std.nat.Succ { prev: .. }` record literal. A qualified name reaches the surface walk in the same dotted spelling whether it is a type or a variant head; the route now asks the registry whether the leaf is a TYPE declared in the named qualifier, records each decision as a census row, and considers only leaves the emitted source actually names (it had also synthesized an unused `DeclarationRef` import from a variant payload). w_qualified_variant_head_earns_no_type_use_line. - `Outcome` x3 and `Rc` E0107: two cuts had each introduced a second per-position renderer for arrow types beside the one fn parameters use. An arrow's return is not a different kind of type from its parameter: both positions now render through render_rust_fn_sig_type, and render_rust_type_with_applied_binding -- which rebuilt its EmitGraphInfo with an empty generic scope, so a fn-scope `C` rendered `_` (E0121) -- carries the fn's generic names through that hop. The measured gate over the second renderer is deleted. w_generic_arrow_return_renders_the_fn_scope_generic; w_arrow_return_type_keeps_its_applied_binding (its fixture was an invalid program: Accepted lacked `diagnostics`). - v2.std.determinism E0425 x2: traced to the bare-name disposition, not the qualified route -- `Determinism` is a type in std.determinism and a variant of v2.lens.registry LensIdV0, and is_known_variant is corpus-wide by spelling, so a TYPE-position reference was delegated to an enum it never named. A name in one of the module's type positions never takes the variant arm. a_known_variant_spelling_in_a_type_position_takes_the_registry_arm (red by construction on the old arm); the harness row is a positive control and says so, because the witness harness refuses any pool carrying the colliding variant with NoSuchVariable. Verified on a test binary built from the self-emitted emitter (not a regeneration): witnesses 23/24 -> 24/24 after the harness row was reshaped; closure instrument 2799 -> 2779. The regeneration that binds these to the mirror follows as its own commit after the freeze merge. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...d_call_target_realization_witness_test.dag | 50 ++++++- src/v1/05_emit_rust.dag | 137 +++++++++++------- ...erived_disposition_census_witness_test.dag | 33 ++++- 3 files changed, 156 insertions(+), 64 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index a5f78c03c3d..a42610a4669 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -278,14 +278,15 @@ test fn w_witness_carrier_falls_back_to_the_fn_return_when_the_value_identity_is // FOLD ACCUMULATOR, THE DISCRIMINATING RED. A fold whose init is empty_map() took the Map // declaration's own formals as its accumulator and wrote them into the turbofish: -// `v1_rt::rc_empty_map::()`. THE PROBE IMPORTS NOTHING ON PURPOSE: it mirrors +// `v1_rt::rc_empty_map::()`. THE PROBE IMPORTS ONLY `Symbol` (the harness pool is the probe's +// import closure, so an unimported `Symbol` refuses there while the whole corpus binds it): it mirrors // v2.lens.unit_modeling, which resolves Map, Symbol, empty_map and map_insert by namespace alone -- // under an explicit `import std.types { Map }` the accumulator resolves to the kernel container and // the defect never fires (measured: that probe emitted `rc_empty_map::` on the // defective compiler). The init must decline the formals exactly as the lambda beside it does. test fn w_fold_empty_map_init_renders_the_resolved_accumulator_not_the_declaration_formals() -> Bool { compile_dag_rust_emit_check( - "module test.claim.fold_accumulator_probe\n\ntype Row {\n field: Symbol\n carrier: Symbol\n}\n\ndata rows: List = [\n Row { field: ^a, carrier: ^b }\n]\n\nfn probe() -> Map {\n fold(rows, init: empty_map(), f: fn(acc, row) {\n map_insert(m: acc, key: row.field, value: row.carrier)\n })\n}\n", + "module test.claim.fold_accumulator_probe\nimport v2.std.node { Symbol }\n\ntype Row {\n field: Symbol\n carrier: Symbol\n}\n\ndata rows: List = [\n Row { field: ^a, carrier: ^b }\n]\n\nfn probe() -> Map {\n fold(rows, init: empty_map(), f: fn(acc, row) {\n map_insert(m: acc, key: row.field, value: row.carrier)\n })\n}\n", "src/test_claim_fold_accumulator_probe.rs", ["rc_empty_map::<"], ["rc_empty_map::"] @@ -323,26 +324,59 @@ test fn w_zero_param_alias_in_an_arrow_return_renders_without_its_rhs_arguments( // honours the binding and must be what an arrow's positions render through. test fn w_arrow_return_type_keeps_its_applied_binding() -> Bool { compile_dag_rust_emit_check( - "module test.claim.arrow_binding_probe\nimport std.types { Int, String }\nimport v2.std.diagnostic { Outcome, Accepted }\ntype Box2 { v: T }\nfn probe() -> fn(Int) -> Outcome> { fn(n) { Accepted { value: Box2 { v: \"x\" } } } }\n", + "module test.claim.arrow_binding_probe\nimport std.types { Int, String }\nimport v2.std.diagnostic { Outcome, Accepted }\ntype Box2 { v: T }\nfn probe() -> fn(Int) -> Outcome> { fn(n) { Accepted { value: Box2 { v: \"x\" }, diagnostics: None } } }\n", "src/test_claim_arrow_binding_probe.rs", ["Box2"], ["Rc>"] ) } -// QUALIFIED TYPE REFERENCE, THE DISCRIMINATING RED. A field typed `std.determinism.Determinism` -// with no import renders as bare `Determinism`, and the use-line derivation collected the DOTTED -// spelling, which is never an emitted token, so the module referenced a name it never imported. -// The leaf must earn its use-line from the qualified registry row. +// QUALIFIED TYPE REFERENCE, POSITIVE CONTROL ONLY. A field typed `std.determinism.Determinism` with +// no import renders as bare `Determinism` and must earn `use crate::std_determinism::{Determinism};`. +// The defect that opened this class (v2.std.determinism, E0425 x2 on the whole closure) fires only +// when the pool also carries a coproduct with a VARIANT spelled `Determinism` (v2.lens.registry +// LensIdV0): the bare-name disposition classified the type-position leaf as that variant. This +// harness cannot carry that pool -- it refuses any probe whose closure includes such a module with +// NoSuchVariable (reproduced with a data-free fixture coproduct; the same probe compiles and earns +// the line from the CLI), so this row is satisfied by the unfixed emitter too and is NOT the class's +// discriminating red. That red is a_known_variant_spelling_in_a_type_position_takes_the_registry_arm +// in src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag (the disposition at +// function grain, red by construction on the variant arm) together with the closure count of the +// use-line in v2_std_determinism.rs. test fn w_qualified_type_reference_earns_the_leaf_use_line() -> Bool { compile_dag_rust_emit_check( "module test.claim.qualified_type_ref_probe\nimport std.types { String }\ntype Fact { signature: String, classification: std.determinism.Determinism }\nfn probe(f: Fact) -> std.determinism.Determinism { f.classification }\n", "src/test_claim_qualified_type_ref_probe.rs", - ["use crate::std_determinism::Determinism;"], + ["use crate::std_determinism::{Determinism};"], ["std.determinism.Determinism"] ) } +// QUALIFIED VALUE HEAD, THE OTHER DIRECTION. `v2.std.nat.Succ { prev: .. }` is a variant record +// literal; the value route imports it through its parent enum, and this route must synthesize +// nothing for it (E0603 `variant import is private`, sixteen sites on the first regeneration). +test fn w_qualified_variant_head_earns_no_type_use_line() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.qualified_variant_head_probe\nimport v2.std.nat { Nat, Zero }\nfn probe() -> Nat { v2.std.nat.Succ { prev: Zero } }\n", + "src/test_claim_qualified_variant_head_probe.rs", + ["Succ"], + ["use crate::v2_std_nat::Succ;"] + ) +} + +// GENERIC ARROW RETURN. A fn-scope generic inside an arrow return position rendered by its erased +// inference -- `Rc>` (v2.std.staging +// then_outcome, three sites) -- while the same shape in a parameter position rendered `C`. Both +// positions now ask the fn-signature renderer. +test fn w_generic_arrow_return_renders_the_fn_scope_generic() -> Bool { + compile_dag_rust_emit_check( + "module test.claim.generic_arrow_probe\nimport v2.std.diagnostic { Outcome, Accepted, Rejected }\nfn then2(f: fn(A) -> Outcome, g: fn(B) -> Outcome) -> fn(A) -> Outcome {\n fn(a) { match f(a) { Accepted { value: b, diagnostics: _ } => g(b) Rejected { diagnostics: d } => Rejected { diagnostics: d } } }\n}\n", + "src/test_claim_generic_arrow_probe.rs", + ["-> Rc Rc>>"], + ["UNRESOLVED_"] + ) +} + // SERVICE OP WITHOUT A REALIZATION, THE DISCRIMINATING RED. `Filesystem.Read(path:)` inside a fn // the signature authority judged service-free emitted `filesystem.read(path).await?` -- an unbound // name in a non-async fn, the only `.await?` in the whole closure. It is a host seam with no diff --git a/src/v1/05_emit_rust.dag b/src/v1/05_emit_rust.dag index 6dcc0945adc..6705b8f3d8f 100644 --- a/src/v1/05_emit_rust.dag +++ b/src/v1/05_emit_rust.dag @@ -226,39 +226,23 @@ fn render_rust_type(n: Node, shared_types: Set, source_indices: Map Outcome>` came out as -// `Rc Rc>>>` -- the inner binding dropped (E0107 missing -// generics for struct `Medium`, v2.compiler.compile stage_translate). The callable template and the -// void arm are the same rows render_node_type consumes; only the per-position renderer changes. -// AN ARROW POSITION DEVIATES FROM THE TARGET-GENERIC RENDERER ONLY FOR THE TWO SHAPES THAT RENDERER -// CANNOT SPELL, AND THIS GATE IS MEASURED, NOT ASSUMED. The first cut routed EVERY arrow position -// through render_rust_type, and the regenerated seed then emitted 2790 rustc refusals on the -// 00_compile closure where the committed bytes had 15: the Rust renderer realizes a v2-declared -// Symbol/String structurally (Rc>, E0308 by the hundreds) and renders an out-of-scope -// type variable as `_` (E0121 inside fn signatures) -- spellings the generic renderer had been -// supplying at those positions, and which nothing in this change set out to alter. So a position -// takes the Rust renderer only when its subtree carries an applied-type binding the generic -// renderer would drop (the `Rc` E0107 class) or is itself a zero-parameter alias carrying -// its right-hand side's children (the `CompileLensOutcome<..>` E0107 class); every other position -// renders exactly as before this change. The deviation set is therefore the defect set. +// the Rust renderers exist to honour: `fn(ResolvedTree) -> Outcome>` came out as +// `Rc Rc>>>` (E0107, v2.compiler.compile stage_translate). +// Two earlier cuts each introduced a SECOND per-position renderer beside the parameter side's: +// routing every position through render_rust_type rendered a fn-scope generic by its erased +// inference (`Outcome`, v2.std.staging then_outcome), +// and a gate that admitted only applied-binding subtrees kept that defect for exactly those +// subtrees while re-opening `Rc` for the rest. The parameter side of the same arrow -- +// emit_rust_param_type's `impl Fn(A) -> Rc>` -- had rendered both shapes correctly all +// along, through render_rust_fn_sig_type in the fn's generic scope. An arrow's return is not a +// different kind of type from an arrow's parameter, so both positions ask that renderer, and the +// defect set is whatever that renderer gets wrong, which the parameter side already measures. +// The callable template and the void arm are the same rows render_node_type consumes. fn render_rust_arrow_position(n: Node, shared_types: Set, source_indices: Map, emit_info: EmitGraphInfo) -> String { - let is_bare_zero_param_alias = n.connective == NoConnective && n.children |> count > 0 && closed_alias_peels_zero_param(env: emit_info.fn_type_env, n: n) - if type_node_carries_applied_binding(n: n, source_indices: source_indices) || is_bare_zero_param_alias { - render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info) - } else { - render_node_type(n: n, target: Rust, shared_types: shared_types, source_indices: source_indices) - } -} - -fn type_node_carries_applied_binding(n: Node, source_indices: Map) -> Bool { - let own = match find_property(props: n.properties, prop_name: "__applied_type_args", source_indices: source_indices) { - Present { value: applied } => applied.children |> count > 0 - Absent => false - } - own || n.children |> any(c => type_node_carries_applied_binding(n: child_type_node(ch: c), source_indices: source_indices)) + render_rust_fn_sig_type(n: n, generic_param_names: emit_info.fn_generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: emit_info.variant_to_enum, env: emit_info.fn_type_env) } // Named rather than inlined because `if x == Variant {` parses as a record literal in .dag. @@ -1284,7 +1268,7 @@ fn render_rust_decl_type(n: Node, generic_param_names: List, shared_type } else if type_node_has_unbound_type_variable(n: n, generic_param_names: generic_param_names, source_indices: source_indices) { "_" } else { - render_rust_type_with_applied_binding(n: n, shared_types: shared_types, source_indices: source_indices, env: env) + render_rust_type_with_applied_binding_in_scope(n: n, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices, env: env) } } } @@ -3858,6 +3842,12 @@ fn local_coproduct_variant_names(items: List, source_indices: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, type_summaries: Map, variant_to_enum: Map) -> ReferenceDerivedCandidateDisposition { - if is_known_variant(type_summaries: type_summaries, name: name) { +fn reference_derived_candidate_disposition(name: String, this_module_name: String, registry: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex, type_summaries: Map, variant_to_enum: Map, in_type_position: Bool) -> ReferenceDerivedCandidateDisposition { + if is_known_variant(type_summaries: type_summaries, name: name) && !in_type_position { match map_get(variant_to_enum, name) { Present { value: parent } => if parent == "" { CandidateVariantParentUnresolved } @@ -4182,6 +4172,7 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< let value_names = unique_strings(items: items |> flat_map(item => collect_value_ref_names(n: item, source_indices: source_indices, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum))) let item_emit_surface_names = items |> flat_map(item => collect_item_emit_surface_names(item: item, source_indices: source_indices, emit_info: emit_info)) let type_surface_names = unique_strings(items: item_emit_surface_names) + let type_position_set = type_surface_names |> fold(init: empty_map(), f: (acc, nm) => map_insert(acc, nm, true)) let field_surface_names = collect_items_field_import_surface_names(surface_names: item_emit_surface_names, emit_info: emit_info) let variant_payload_structs = expand_variant_payload_struct_imports(names: type_surface_names, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum) let emitter_attested_anon_heads = unique_strings(items: items |> flat_map(item => collect_anonymous_record_lit_heads(n: item, source_indices: source_indices, type_summaries: emit_info.type_summaries))) @@ -4210,7 +4201,7 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< [ReferenceDerivedCandidateRow { module_name: this_module_name, name: name, - disposition: reference_derived_candidate_disposition(name: name, this_module_name: this_module_name, registry: registry, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum) + disposition: reference_derived_candidate_disposition(name: name, this_module_name: this_module_name, registry: registry, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index, type_summaries: emit_info.type_summaries, variant_to_enum: emit_info.variant_to_enum, in_type_position: emit_map_has(m: type_position_set, key: name)) }] } ) @@ -4234,7 +4225,7 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< let block_lines = if block == "" { [] } else { block |> split(delimiter: "\n") } let emitted_here = block_lines |> flat_map(l => imported_names_in_use_line(line: l)) let fallback = names |> flat_map(nm => - if (emitted_here |> any(e => e == nm)) || is_known_variant(type_summaries: emit_info.type_summaries, name: nm) { + if (emitted_here |> any(e => e == nm)) || (is_known_variant(type_summaries: emit_info.type_summaries, name: nm) && !emit_map_has(m: type_position_set, key: nm)) { [] } else if provider_proven_exports_symbol(name: nm, provider_module: provider, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { [concat(rust_visibility_prefix(), concat("use crate::", concat(module_to_filename(name: provider), concat("::", concat(emit_import_name(n: nm, registry: registry), ";")))))] @@ -4245,37 +4236,72 @@ fn reference_derived_use_line_plan(items: List, unlisted_type_names: List< concat(block_lines, fallback) ) let names_already_in_lines = lines |> flat_map(l => imported_names_in_use_line(line: l)) - let qualified_lines = qualified_type_reference_use_lines(names: type_surface_names, this_module_name: this_module_name, already: already, names_already_in_lines: names_already_in_lines, registry: registry, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) - ReferenceDerivedUseLinePlan { lines: concat(lines, qualified_lines), rows: rows } + let qualified_rows = qualified_type_reference_rows(names: type_surface_names |> filter(nm => emit_map_has(m: emitted_source_token_set, key: qualified_last_segment(name: nm))), this_module_name: this_module_name, already: already, names_already_in_lines: names_already_in_lines, registry: registry, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) + let qualified_lines = qualified_type_reference_use_lines(rows: qualified_rows, registry: registry) + ReferenceDerivedUseLinePlan { lines: concat(lines, qualified_lines), rows: concat(rows, qualified_rows) } } } // A QUALIFIED TYPE REFERENCE REACHES EMISSION AS ITS LEAF AND NEEDS THE LEAF'S USE-LINE. The type -// renderers spell `std.determinism.Determinism` as bare `Determinism` (rust_fn_sig_leaf_name), and -// the surface walk collects the DOTTED spelling -- which is never an identifier token in the emitted -// source, so the candidate filter dropped it before any disposition was assigned and the module -// referenced a name it never imported (E0425 cannot find type `Determinism`, v2.std.determinism, -// two sites). The qualifier IS the provider the author named, so the line is synthesized from it +// renderers spell `std.determinism.Determinism` as bare `Determinism` (rust_fn_sig_leaf_name). A +// reference the resolver binds reaches the surface walk as that leaf and is decided by the +// bare-name route above; a reference the resolver leaves authored reaches it in its DOTTED spelling +// -- never an identifier token in the emitted source, so the candidate filter dropped it before any +// disposition was assigned. This route decides the dotted ones. (The v2.std.determinism E0425 that +// motivated it was the OTHER case, measured by tracing this route's inputs: the leaf arrived bare +// and the bare-name route classified it as the v2.lens.registry VARIANT of the same spelling; that +// is the type-position exemption in reference_derived_candidate_disposition, not this route.) The qualifier IS the provider the author named, so the line is synthesized from it // directly -- under the same construction wall every other synthesized use-line passes: // provider_proven_exports_symbol must hold for the leaf on that module, or nothing is emitted and // the name stays a loud unresolved symbol. A first cut keyed this on the qualified item-registry // overlay instead; that overlay carries no row for the reference and the cut was a measured // NON-EVENT (falsifier m12 reddened nothing; the two sites stayed), so it is replaced, not kept. -fn qualified_type_reference_use_lines(names: List, this_module_name: String, already: Map, names_already_in_lines: List, registry: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { +// THE SURFACE WALK ALSO COLLECTS QUALIFIED VALUE HEADS, AND THOSE ARE NOT THIS ROUTE'S. The first +// regeneration of this function synthesized `pub use crate::v2_std_nat::Succ;` for every +// `v2.std.nat.Succ { prev: .. }` record literal (E0603, sixteen sites): a variant reaches the surface +// walk in the same dotted spelling as a type, and Rust admits a variant only through its parent +// enum, which the value route already imports. So the leaf must be a TYPE the registry declares in +// the named qualifier before any line is synthesized; every other qualified name is the value +// route's, and this route says nothing about it. Each decision this route does take is a census row +// beside the bare-name rows -- the qualified spelling is the row's name, so the two never collide. +fn qualified_type_reference_rows(names: List, this_module_name: String, already: Map, names_already_in_lines: List, registry: Map, export_sets: Map>, typed_modules: List, source_indices: Map, module_index: ModuleIndex) -> List { let leaves_done = names_already_in_lines |> fold(init: empty_map(), f: (acc, nm) => map_insert(acc, nm, true)) - unique_strings(items: names |> flat_map(name => + names |> flat_map(name => if !string_contains(s: name, pattern: ".") { [] } else { let leaf = qualified_last_segment(name: name) let segments = name |> split(delimiter: ".") let qualifier = segments |> take(n: (segments |> count) - 1) |> join(separator: ".") if qualifier == this_module_name || emit_map_has(m: already, key: leaf) || emit_map_has(m: leaves_done, key: leaf) || is_kernel_type(name: leaf) { [] - } else if provider_proven_exports_symbol(name: leaf, provider_module: qualifier, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { - [concat(rust_visibility_prefix(), "use crate::", module_to_filename(name: qualifier), "::", emit_import_name(n: leaf, registry: registry), ";")] } else { - [] + match map_get(registry, leaf) { + Absent => [ReferenceDerivedCandidateRow { module_name: this_module_name, name: name, disposition: CandidateRegistryAbsent }] + Present { value: info } => + if !(registry_row_is_type_declared_in(info: info, module_name: qualifier)) { + [] + } else if provider_proven_exports_symbol(name: leaf, provider_module: qualifier, export_sets: export_sets, typed_modules: typed_modules, source_indices: source_indices, module_index: module_index) { + [ReferenceDerivedCandidateRow { module_name: this_module_name, name: name, disposition: CandidateSurvived { provider_module: qualifier } }] + } else { + [ReferenceDerivedCandidateRow { module_name: this_module_name, name: name, disposition: CandidateExportProofFailed { provider_module: qualifier } }] + } + } } } + ) +} + +// Named because `info.kind == TypeItem` is a comparison the .dag surface reads as a record literal. +fn registry_row_is_type_declared_in(info: ItemInfo, module_name: String) -> Bool { + if info.module_name != module_name { false } else { match info.kind { TypeItem => true _ => false } } +} + +fn qualified_type_reference_use_lines(rows: List, registry: Map) -> List { + unique_strings(items: rows |> flat_map(r => + match r.disposition { + CandidateSurvived { provider_module: provider } => + [concat(rust_visibility_prefix(), "use crate::", module_to_filename(name: provider), "::", emit_import_name(n: qualified_last_segment(name: r.name), registry: registry), ";")] + _ => [] + } )) } @@ -6574,7 +6600,16 @@ fn emit_struct_from_children(name: String, type_params: String, generic_param_na data render_rust_type_applied_binding_env_note: String = "Construction wall for the zero-parameter-alias applied-argument class (E0107 'type alias takes 0 generic arguments but N were supplied'). A reference to a closed alias arrives at the emitter carrying the RESOLVED DEFINITION's type arguments as its children while its authored spelling is still the alias name, so a renderer that prints name-plus-children emits ClosedCarrierAlias for a Rust alias declared with no parameters. Four renderers already refuse that shape by asking the single peel authority closed_alias_peel_verdict: render_rust_applied_type, render_rust_decl_type, render_rust_fn_sig_type and render_rust_alias_rhs_type. This function is the fifth path, and it did NOT lack the guard -- it reached render_rust_applied_type, which asked, and was answered with an EMPTY TypeEnv this function constructed inline plus an empty_emit_graph_info() it passed to render_rust_type. An empty env resolves no binding, and the peel predicate renders 'I could not look this up' identically to 'this declaration has parameters' -- the state-space conflation DESIGN section 5 names, failing open into the widened applied form rather than refusing. Every one of this function's callers already holds the TypeEnv it was discarding, so the fix is to stop discarding it: the peel authority stays the single authority and is simply answered truthfully. Measured on the src/v2/compiler/03_ingest.dag closure. The next rung is upstream and not taken here: an alias reference that preserved its AUTHORED arity would make the bad shape unwritable rather than merely refused, at which point no renderer would need to ask at all." +// THE FN'S GENERIC SCOPE MUST SURVIVE THIS HOP. render_rust_decl_type reaches here from a fn +// signature carrying generic_param_names, and the EmitGraphInfo rebuilt below used to carry an +// empty scope, so a fn-scope generic inside an arrow return (`fn(A) -> Outcome`) rendered as +// `_` (E0121) or by its erased inference; the parameter side of the same arrow rendered `C`. +// The scope-free spelling stays for the callers that have no fn scope (fields, data, wire rows). fn render_rust_type_with_applied_binding(n: Node, shared_types: Set, source_indices: Map, env: TypeEnv) -> String { + render_rust_type_with_applied_binding_in_scope(n: n, generic_param_names: [], shared_types: shared_types, source_indices: source_indices, env: env) +} + +fn render_rust_type_with_applied_binding_in_scope(n: Node, generic_param_names: List, shared_types: Set, source_indices: Map, env: TypeEnv) -> String { if is_host_text_carrier_type(n: n, source_indices: source_indices) { return rust_carrier_optional_wrap(n: n, rendered: "String") } match find_property(props: n.properties, prop_name: "__applied_type_args", source_indices: source_indices) { Present { value: applied } => @@ -6585,15 +6620,15 @@ fn render_rust_type_with_applied_binding(n: Node, shared_types: Set, sou if outer_name != applied_name { render_rust_shared_type_with_optional(n: n, type_name: outer_name, rendered: outer_name, shared_types: shared_types) } else { - render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, source_indices: source_indices, variant_to_enum: empty_map(), env: env) + render_rust_applied_type_shared(n: applied, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: empty_map(), env: env) } } else { - render_rust_applied_type_shared(n: applied, generic_param_names: [], shared_types: shared_types, source_indices: source_indices, variant_to_enum: empty_map(), env: env) + render_rust_applied_type_shared(n: applied, generic_param_names: generic_param_names, shared_types: shared_types, source_indices: source_indices, variant_to_enum: empty_map(), env: env) } } else { - render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info_with_fn_type_context(emit_info: empty_emit_graph_info(), generic_param_names: [], env: env)) + render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info_with_fn_type_context(emit_info: empty_emit_graph_info(), generic_param_names: generic_param_names, env: env)) } - Absent => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info_with_fn_type_context(emit_info: empty_emit_graph_info(), generic_param_names: [], env: env)) + Absent => render_rust_type(n: n, shared_types: shared_types, source_indices: source_indices, emit_info: emit_info_with_fn_type_context(emit_info: empty_emit_graph_info(), generic_param_names: generic_param_names, env: env)) } } diff --git a/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag b/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag index 895e408187d..3949fcf8f4a 100644 --- a/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag +++ b/src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag @@ -58,7 +58,8 @@ fn fixture_disposition(registry: Map, export_sets: Map Bool { source_indices: empty_map(), module_index: build_module_index(modules: []), type_summaries: empty_map(), - variant_to_enum: empty_map() + variant_to_enum: empty_map(), + in_type_position: false ) == CandidateSurvived { provider_module: "fixture.provider" } } @@ -136,7 +138,8 @@ test fn known_variant_is_delegated_to_its_parent_not_registry_absent() -> Bool { source_indices: empty_map(), module_index: build_module_index(modules: []), type_summaries: fixture_variant_type_summaries(), - variant_to_enum: map_insert(empty_map(), "V", "E") + variant_to_enum: map_insert(empty_map(), "V", "E"), + in_type_position: false ) == CandidateVariantDelegatedToParent { parent_enum: "E" } } @@ -165,10 +168,29 @@ test fn a_variant_whose_parent_is_ambiguous_is_not_delegated_to_nothing() -> Boo source_indices: empty_map(), module_index: build_module_index(modules: []), type_summaries: fixture_colliding_variant_type_summaries(), - variant_to_enum: map_insert(empty_map(), "V", "") + variant_to_enum: map_insert(empty_map(), "V", ""), + in_type_position: false ) == CandidateVariantParentUnresolved } +// A TYPE POSITION CANNOT HOLD A VARIANT. The same spelling `V` that the whole-corpus type summaries +// know as a variant, referenced from one of the module's type positions, is decided by the registry +// arm -- here registry-absent, never delegated to an enum the position could not name. +test fn a_known_variant_spelling_in_a_type_position_takes_the_registry_arm() -> Bool { + reference_derived_disposition_name(disposition: reference_derived_candidate_disposition( + name: "V", + this_module_name: "fixture.consumer", + registry: empty_map(), + export_sets: empty_map(), + typed_modules: [], + source_indices: empty_map(), + module_index: build_module_index(modules: []), + type_summaries: fixture_variant_type_summaries(), + variant_to_enum: map_insert(empty_map(), "V", "E"), + in_type_position: true + )) == "registry-absent" +} + test fn an_unresolved_parent_is_not_reported_as_registry_absent() -> Bool { reference_derived_disposition_name(disposition: CandidateVariantParentUnresolved) != "registry-absent" } @@ -183,7 +205,8 @@ test fn non_variant_name_still_answers_registry_absent() -> Bool { source_indices: empty_map(), module_index: build_module_index(modules: []), type_summaries: fixture_variant_type_summaries(), - variant_to_enum: map_insert(empty_map(), "V", "E") + variant_to_enum: map_insert(empty_map(), "V", "E"), + in_type_position: false )) == "registry-absent" } From c2dadc85dd441f514a0222a780c93c88ffc0697b Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 20:38:06 +0000 Subject: [PATCH 29/30] Regenerate the stage0 mirror at the 49482b0 freeze: byte fixed point at round 3, three paths, each explained by an authority change srv1 (/tmp/xl0e2.sh -> /tmp/xl0j2.log, launched 2026-08-29T19:52:56Z), criterion = every regen-population file byte-equal to installed; the full workspace rebuilt as the gate each round. round 1 gunbc=14967ca810cb6609 from installed db46176cc5cf5861 -> v1_compiler_emit_rust.rs, v1_tests_claim_reference_derived_disposition_census_witness_test.rs round 2 gunbc=5378a516528a6e0c from installed efa440bc86734f53 -> v1_compiler_trait_derive_emit.rs round 3 gunbc=974aafe864f743f6 from installed b1a0409ce9fc79d4 -> BYTE FIXED POINT v1_compiler_emit_rust.rs <- 05_emit_rust.dag (arrow positions via the fn-signature renderer, generic scope through the applied-binding hop, type-position exemption, qualified rows with the registry type gate and token filter) v1_tests_claim_reference_derived_disposition_census_witness_test.rs <- its .dag (in_type_position at 5 callers + the type-position control) v1_compiler_trait_derive_emit.rs <- retracts the unused `pub use crate::std_types::List;` the earlier qualified route synthesized (token filter) Final installed tree b1a0409ce9fc79d4; merged tree 89c55a0e7e8d949047b5d92864dfc9fe306aebc0 at the freeze; main parent 5e80671. No hand edit to any generated file. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- src/v1/stage0/src/v1_compiler_emit_rust.rs | 280 +++++++++++++----- .../src/v1_compiler_trait_derive_emit.rs | 1 - ...derived_disposition_census_witness_test.rs | 26 ++ 3 files changed, 224 insertions(+), 83 deletions(-) diff --git a/src/v1/stage0/src/v1_compiler_emit_rust.rs b/src/v1/stage0/src/v1_compiler_emit_rust.rs index 9f85f01ae36..d94b5921a40 100644 --- a/src/v1/stage0/src/v1_compiler_emit_rust.rs +++ b/src/v1/stage0/src/v1_compiler_emit_rust.rs @@ -325,57 +325,14 @@ pub fn render_rust_arrow_position( source_indices: Rc>>, emit_info: Rc, ) -> String { - { - let is_bare_zero_param_alias = (((n.connective.clone() == Connective::NoConnective) - && ((n.children.clone().len() as i64) > 0)) - && closed_alias_peels_zero_param(emit_info.fn_type_env.clone(), n.clone())); - if (type_node_carries_applied_binding(n.clone(), source_indices.clone()) - || is_bare_zero_param_alias.clone()) - { - render_rust_type( - n.clone(), - shared_types.clone(), - source_indices.clone(), - emit_info.clone(), - ) - } else { - crate::v1_compiler_emit::render_node_type( - n.clone(), - RenderTarget::Rust, - shared_types.clone(), - source_indices.clone(), - ) - } - } -} - -pub fn type_node_carries_applied_binding( - n: Rc, - source_indices: Rc>>, -) -> bool { - stacker::maybe_grow(512 * 1024, 2 * 1024 * 1024, || { - let own = match crate::v1_std_core::find_property( - n.properties.clone(), - "__applied_type_args".to_string(), - source_indices.clone(), - ) { - Some(applied) => ((applied.children.clone().len() as i64) > 0), - None => false, - }; - (own.clone() || { - let mut __found = false; - for c in n.children.clone().iter().cloned() { - if type_node_carries_applied_binding( - crate::v1_compiler_infer_types::child_type_node(c.clone()), - source_indices.clone(), - ) { - __found = true; - break; - } - } - __found - }) - }) + render_rust_fn_sig_type( + n.clone(), + emit_info.fn_generic_param_names.clone(), + shared_types.clone(), + source_indices.clone(), + emit_info.variant_to_enum.clone(), + emit_info.fn_type_env.clone(), + ) } pub fn rust_type_node_is_arrow(n: Rc) -> bool { @@ -2382,8 +2339,9 @@ if peel.clone() { ) { "_".to_string() } else { - render_rust_type_with_applied_binding( + render_rust_type_with_applied_binding_in_scope( n.clone(), + generic_param_names.clone(), shared_types.clone(), source_indices.clone(), env.clone(), @@ -8081,8 +8039,11 @@ pub fn reference_derived_candidate_disposition( module_index: Rc, type_summaries: Rc>>, variant_to_enum: Rc>, + in_type_position: bool, ) -> Rc { - if crate::v1_compiler_infer_emit_info::is_known_variant(type_summaries.clone(), name.clone()) { + if (crate::v1_compiler_infer_emit_info::is_known_variant(type_summaries.clone(), name.clone()) + && !in_type_position.clone()) + { match v1_rt::map_get(&variant_to_enum, name.clone()) { Some(parent) => { if (parent.clone() == "".to_string()) { @@ -8380,6 +8341,12 @@ pub fn reference_derived_use_line_plan( }); let type_surface_names = crate::v1_compiler_emit_core_support::unique_strings(item_emit_surface_names.clone()); + let type_position_set = type_surface_names.iter().cloned().fold( + v1_rt::rc_empty_map::(), + |acc: Rc>, nm: String| { + v1_rt::rc_map_insert(acc, nm.clone(), true) + }, + ); let field_surface_names = collect_items_field_import_surface_names( item_emit_surface_names.clone(), emit_info.clone(), @@ -8555,6 +8522,10 @@ pub fn reference_derived_use_line_plan( module_index.clone(), emit_info.type_summaries.clone(), emit_info.variant_to_enum.clone(), + crate::v1_compiler_infer_types::emit_map_has( + type_position_set.clone(), + name.clone(), + ), ), })]) }) @@ -8611,7 +8582,7 @@ let block_lines = if (block.clone() == "".to_string()) { Rc::new(block.clone().split(&"\n".to_string()).map(|s| s.to_string()).collect::>()) }; let emitted_here = Rc::new({ let mut __result = Vec::new(); for l in block_lines.iter().cloned() { __result.extend((*imported_names_in_use_line(l.clone())).iter().cloned()); } __result }); -let fallback = Rc::new({ let mut __result = Vec::new(); for nm in names.iter().cloned() { __result.extend((*if ({ let mut __found = false; for e in emitted_here.iter().cloned() { if (e.clone() == nm.clone()) { __found = true; break; } } __found } || crate::v1_compiler_infer_emit_info::is_known_variant(emit_info.type_summaries.clone(), nm.clone())) { +let fallback = Rc::new({ let mut __result = Vec::new(); for nm in names.iter().cloned() { __result.extend((*if ({ let mut __found = false; for e in emitted_here.iter().cloned() { if (e.clone() == nm.clone()) { __found = true; break; } } __found } || (crate::v1_compiler_infer_emit_info::is_known_variant(emit_info.type_summaries.clone(), nm.clone()) && !crate::v1_compiler_infer_types::emit_map_has(type_position_set.clone(), nm.clone()))) { Rc::new(vec![]) } else { if provider_proven_exports_symbol(nm.clone(), provider.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone()) { @@ -8632,8 +8603,19 @@ v1_rt::concat(block_lines.clone(), fallback.clone()) } __result }); - let qualified_lines = qualified_type_reference_use_lines( - type_surface_names.clone(), + let qualified_rows = qualified_type_reference_rows( + Rc::new({ + let mut __result = Vec::new(); + for nm in type_surface_names.iter().cloned() { + if crate::v1_compiler_infer_types::emit_map_has( + emitted_source_token_set.clone(), + crate::v1_std_core::qualified_last_segment(nm.clone()), + ) { + __result.push(nm); + } + } + __result + }), this_module_name.clone(), already.clone(), names_already_in_lines.clone(), @@ -8643,14 +8625,16 @@ v1_rt::concat(block_lines.clone(), fallback.clone()) source_indices.clone(), module_index.clone(), ); + let qualified_lines = + qualified_type_reference_use_lines(qualified_rows.clone(), registry.clone()); Rc::new(ReferenceDerivedUseLinePlan { lines: v1_rt::concat(lines.clone(), qualified_lines.clone()), - rows: rows.clone(), + rows: v1_rt::concat(rows.clone(), qualified_rows.clone()), }) } } -pub fn qualified_type_reference_use_lines( +pub fn qualified_type_reference_rows( names: Rc>, this_module_name: String, already: Rc>, @@ -8660,7 +8644,7 @@ pub fn qualified_type_reference_use_lines( typed_modules: Rc>>, source_indices: Rc>>, module_index: Rc, -) -> Rc> { +) -> Rc>> { { let leaves_done = names_already_in_lines.iter().cloned().fold( v1_rt::rc_empty_map::(), @@ -8668,33 +8652,149 @@ pub fn qualified_type_reference_use_lines( v1_rt::rc_map_insert(acc, nm.clone(), true) }, ); - crate::v1_compiler_emit_core_support::unique_strings(Rc::new({ + Rc::new({ let mut __result = Vec::new(); for name in names.iter().cloned() { - __result.extend((*if !v1_rt::string_contains(&name, ".".to_string()) { - Rc::new(vec![]) - } else { - { - let leaf = crate::v1_std_core::qualified_last_segment(name.clone()); -let segments = Rc::new(name.clone().split(&".".to_string()).map(|s| s.to_string()).collect::>()); -let qualifier = Rc::new(segments.clone().iter().cloned().take(((segments.clone().len() as i64) - 1) as usize).collect::>()).join(&".".to_string()); -if ((((qualifier.clone() == this_module_name.clone()) || crate::v1_compiler_infer_types::emit_map_has(already.clone(), leaf.clone())) || crate::v1_compiler_infer_types::emit_map_has(leaves_done.clone(), leaf.clone())) || crate::std_types::is_kernel_type(leaf.clone())) { - Rc::new(vec![]) - } else { - if provider_proven_exports_symbol(leaf.clone(), qualifier.clone(), export_sets.clone(), typed_modules.clone(), source_indices.clone(), module_index.clone()) { - Rc::new(vec![v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(v1_rt::concat(rust_visibility_prefix(), "use crate::".to_string()), crate::v1_compiler_emit_core_support::module_to_filename(qualifier.clone())), "::".to_string()), emit_import_name(leaf.clone(), registry.clone())), ";".to_string())]) - } else { + __result.extend( + (*if !v1_rt::string_contains(&name, ".".to_string()) { Rc::new(vec![]) - } - } -} - }).iter().cloned()); + } else { + { + let leaf = crate::v1_std_core::qualified_last_segment(name.clone()); + let segments = Rc::new( + name.clone() + .split(&".".to_string()) + .map(|s| s.to_string()) + .collect::>(), + ); + let qualifier = Rc::new( + segments + .clone() + .iter() + .cloned() + .take(((segments.clone().len() as i64) - 1) as usize) + .collect::>(), + ) + .join(&".".to_string()); + if ((((qualifier.clone() == this_module_name.clone()) + || crate::v1_compiler_infer_types::emit_map_has( + already.clone(), + leaf.clone(), + )) + || crate::v1_compiler_infer_types::emit_map_has( + leaves_done.clone(), + leaf.clone(), + )) + || crate::std_types::is_kernel_type(leaf.clone())) + { + Rc::new(vec![]) + } else { + match v1_rt::map_get(®istry, leaf.clone()) { + None => Rc::new(vec![Rc::new(ReferenceDerivedCandidateRow { + module_name: this_module_name.clone(), + name: name.clone(), + disposition: Rc::new(ReferenceDerivedCandidateDisposition::CandidateRegistryAbsent), +})]), + Some(info) => { + if !registry_row_is_type_declared_in( + info.clone(), + qualifier.clone(), + ) { + Rc::new(vec![]) + } else { + if provider_proven_exports_symbol( + leaf.clone(), + qualifier.clone(), + export_sets.clone(), + typed_modules.clone(), + source_indices.clone(), + module_index.clone(), + ) { + Rc::new(vec![Rc::new(ReferenceDerivedCandidateRow { + module_name: this_module_name.clone(), + name: name.clone(), + disposition: Rc::new(ReferenceDerivedCandidateDisposition::CandidateSurvived { + provider_module: qualifier.clone(), +}), +})]) + } else { + Rc::new(vec![Rc::new(ReferenceDerivedCandidateRow { + module_name: this_module_name.clone(), + name: name.clone(), + disposition: Rc::new(ReferenceDerivedCandidateDisposition::CandidateExportProofFailed { + provider_module: qualifier.clone(), +}), +})]) + } + } + } + } + } + } + }) + .iter() + .cloned(), + ); } __result - })) + }) } } +pub fn registry_row_is_type_declared_in(info: Rc, module_name: String) -> bool { + if (info.module_name.clone() != module_name.clone()) { + false + } else { + match info.kind.clone() { + ItemKind::TypeItem => true, + _ => false, + } + } +} + +pub fn qualified_type_reference_use_lines( + rows: Rc>>, + registry: Rc>>, +) -> Rc> { + crate::v1_compiler_emit_core_support::unique_strings(Rc::new({ + let mut __result = Vec::new(); + for r in rows.iter().cloned() { + __result.extend( + (*match (*r.disposition.clone()).clone() { + ReferenceDerivedCandidateDisposition::CandidateSurvived { + provider_module: provider, + .. + } => Rc::new(vec![v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + v1_rt::concat( + rust_visibility_prefix(), + "use crate::".to_string(), + ), + crate::v1_compiler_emit_core_support::module_to_filename( + provider.clone(), + ), + ), + "::".to_string(), + ), + emit_import_name( + crate::v1_std_core::qualified_last_segment(r.name.clone()), + registry.clone(), + ), + ), + ";".to_string(), + )]), + _ => Rc::new(vec![]), + }) + .iter() + .cloned(), + ); + } + __result + })) +} + pub fn reference_derived_use_lines( items: Rc>>, unlisted_type_names: Rc>, @@ -14604,6 +14704,22 @@ pub fn render_rust_type_with_applied_binding( shared_types: Rc>, source_indices: Rc>>, env: Rc, +) -> String { + render_rust_type_with_applied_binding_in_scope( + n.clone(), + Rc::new(vec![]), + shared_types.clone(), + source_indices.clone(), + env.clone(), + ) +} + +pub fn render_rust_type_with_applied_binding_in_scope( + n: Rc, + generic_param_names: Rc>, + shared_types: Rc>, + source_indices: Rc>>, + env: Rc, ) -> String { { if is_host_text_carrier_type(n.clone(), source_indices.clone()) { @@ -14637,7 +14753,7 @@ pub fn render_rust_type_with_applied_binding( } else { render_rust_applied_type_shared( applied.clone(), - Rc::new(vec![]), + generic_param_names.clone(), shared_types.clone(), source_indices.clone(), v1_rt::rc_empty_map::(), @@ -14647,7 +14763,7 @@ pub fn render_rust_type_with_applied_binding( } else { render_rust_applied_type_shared( applied.clone(), - Rc::new(vec![]), + generic_param_names.clone(), shared_types.clone(), source_indices.clone(), v1_rt::rc_empty_map::(), @@ -14662,7 +14778,7 @@ pub fn render_rust_type_with_applied_binding( source_indices.clone(), crate::v1_compiler_infer_emit_info::emit_info_with_fn_type_context( crate::v1_compiler_infer_emit_info::empty_emit_graph_info(), - Rc::new(vec![]), + generic_param_names.clone(), env.clone(), ), ) @@ -14674,7 +14790,7 @@ pub fn render_rust_type_with_applied_binding( source_indices.clone(), crate::v1_compiler_infer_emit_info::emit_info_with_fn_type_context( crate::v1_compiler_infer_emit_info::empty_emit_graph_info(), - Rc::new(vec![]), + generic_param_names.clone(), env.clone(), ), ), diff --git a/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs b/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs index 9427918702f..cec8ebda4e1 100644 --- a/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs +++ b/src/v1/stage0/src/v1_compiler_trait_derive_emit.rs @@ -37,7 +37,6 @@ pub use crate::std_trait_derive_shape::{ repr_grounding_derive_completeness_predicate, repr_grounding_group_completion_carrier, repr_grounding_supplemental_bool_host_bridge_target, }; -pub use crate::std_types::List; pub use crate::std_types::{container_template_algebra, is_container_type}; pub use crate::v1_compiler_artifact::RenderTarget; use crate::v1_compiler_artifact::RenderTarget::Rust; diff --git a/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs b/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs index 7525f8971a6..c2455448796 100644 --- a/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs +++ b/src/v1/stage0/src/v1_tests_claim_reference_derived_disposition_census_witness_test.rs @@ -86,6 +86,7 @@ pub fn fixture_disposition( crate::v1_compiler_emit_rust::build_module_index(Rc::new(vec![])), v1_rt::rc_empty_map::>(), v1_rt::rc_empty_map::(), + false, ), ) } @@ -122,6 +123,7 @@ pub fn cross_module_candidate_with_export_proof_survives() -> bool { crate::v1_compiler_emit_rust::build_module_index(Rc::new(vec![])), v1_rt::rc_empty_map::>(), v1_rt::rc_empty_map::(), + false, ) == Rc::new(ReferenceDerivedCandidateDisposition::CandidateSurvived { provider_module: "fixture.provider".to_string(), })) @@ -234,6 +236,7 @@ pub fn known_variant_is_delegated_to_its_parent_not_registry_absent() -> bool { "V".to_string(), "E".to_string(), ), + false, ) == Rc::new( ReferenceDerivedCandidateDisposition::CandidateVariantDelegatedToParent { parent_enum: "E".to_string(), @@ -286,9 +289,31 @@ pub fn a_variant_whose_parent_is_ambiguous_is_not_delegated_to_nothing() -> bool "V".to_string(), "".to_string(), ), + false, ) == Rc::new(ReferenceDerivedCandidateDisposition::CandidateVariantParentUnresolved)) } +pub fn a_known_variant_spelling_in_a_type_position_takes_the_registry_arm() -> bool { + (crate::v1_compiler_emit_rust::reference_derived_disposition_name( + crate::v1_compiler_emit_rust::reference_derived_candidate_disposition( + "V".to_string(), + "fixture.consumer".to_string(), + v1_rt::rc_empty_map::>(), + v1_rt::rc_empty_map::>>(), + Rc::new(vec![]), + v1_rt::rc_empty_map::>(), + crate::v1_compiler_emit_rust::build_module_index(Rc::new(vec![])), + fixture_variant_type_summaries(), + v1_rt::rc_map_insert( + v1_rt::rc_empty_map::(), + "V".to_string(), + "E".to_string(), + ), + true, + ), + ) == "registry-absent".to_string()) +} + pub fn an_unresolved_parent_is_not_reported_as_registry_absent() -> bool { (crate::v1_compiler_emit_rust::reference_derived_disposition_name(Rc::new( ReferenceDerivedCandidateDisposition::CandidateVariantParentUnresolved, @@ -311,6 +336,7 @@ pub fn non_variant_name_still_answers_registry_absent() -> bool { "V".to_string(), "E".to_string(), ), + false, ), ) == "registry-absent".to_string()) } From 466811e7a98c0b5e820cb9faa3d55ca4e19fc98c Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Sat, 29 Aug 2026 21:00:39 +0000 Subject: [PATCH 30/30] Witness fixture only: the qualified-type positive control moves to a provider the harness pool can carry Post-freeze, fixture-only (dag/test/claim is not a regen-population path; a no-drift regen run on this head is recorded in the PR). Two harness facts, both measured on the fixed-point artifact gunbc=974aafe864f743f6: a `{Determinism}` inside a .dag string literal is read as an interpolation of that name (the row failed in the interpreter before any compile ran), and the harness pool is the probe's DECLARED import closure, so a provider referenced only by a dotted name is absent -- and std.determinism cannot enter it because its own body references std.perturbation the same way. The row now uses std.decl_ref with a sibling import and says plainly that it is a positive control; the class's discriminating red stays at the disposition grain (a_known_variant_spelling_in_a_type_position_takes_the_registry_arm) and in the closure count. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_01GXfYKNQTD3VfYyQcnJpxNU --- ...d_call_target_realization_witness_test.dag | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/dag/test/claim/emitted_call_target_realization_witness_test.dag b/dag/test/claim/emitted_call_target_realization_witness_test.dag index a42610a4669..b849d70e533 100644 --- a/dag/test/claim/emitted_call_target_realization_witness_test.dag +++ b/dag/test/claim/emitted_call_target_realization_witness_test.dag @@ -331,24 +331,27 @@ test fn w_arrow_return_type_keeps_its_applied_binding() -> Bool { ) } -// QUALIFIED TYPE REFERENCE, POSITIVE CONTROL ONLY. A field typed `std.determinism.Determinism` with -// no import renders as bare `Determinism` and must earn `use crate::std_determinism::{Determinism};`. -// The defect that opened this class (v2.std.determinism, E0425 x2 on the whole closure) fires only -// when the pool also carries a coproduct with a VARIANT spelled `Determinism` (v2.lens.registry -// LensIdV0): the bare-name disposition classified the type-position leaf as that variant. This -// harness cannot carry that pool -- it refuses any probe whose closure includes such a module with -// NoSuchVariable (reproduced with a data-free fixture coproduct; the same probe compiles and earns -// the line from the CLI), so this row is satisfied by the unfixed emitter too and is NOT the class's -// discriminating red. That red is a_known_variant_spelling_in_a_type_position_takes_the_registry_arm -// in src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag (the disposition at +// QUALIFIED TYPE REFERENCE, POSITIVE CONTROL ONLY. A field typed by a dotted, unimported provider +// name renders as its bare leaf and must earn the leaf's use-line from the provider the author +// named. The defect that opened this class (v2.std.determinism, E0425 x2 on the whole closure) +// fires only when the pool also carries a coproduct with a VARIANT spelled `Determinism` +// (v2.lens.registry LensIdV0): the bare-name disposition classified the type-position leaf as that +// variant. This harness cannot carry that specimen at all -- its pool is the probe's DECLARED +// import closure, so a provider referenced only by a dotted name is absent (hard diagnostic), and +// std.determinism itself references std.perturbation the same way -- so this row uses std.decl_ref +// with a sibling import to bring the provider into the pool, and is satisfied by the unfixed +// emitter too. The class's discriminating red is +// a_known_variant_spelling_in_a_type_position_takes_the_registry_arm in +// src/v1/tests/claim/reference_derived_disposition_census_witness_test.dag (the disposition at // function grain, red by construction on the variant arm) together with the closure count of the -// use-line in v2_std_determinism.rs. +// use-line in v2_std_determinism.rs. The expected line is spelled as two substrings because a +// `{Name}` inside a .dag string literal is read as an interpolation of that name. test fn w_qualified_type_reference_earns_the_leaf_use_line() -> Bool { compile_dag_rust_emit_check( - "module test.claim.qualified_type_ref_probe\nimport std.types { String }\ntype Fact { signature: String, classification: std.determinism.Determinism }\nfn probe(f: Fact) -> std.determinism.Determinism { f.classification }\n", + "module test.claim.qualified_type_ref_probe\nimport std.types { String }\nimport std.decl_ref { DeclField }\ntype Fact { signature: String, r: std.decl_ref.DeclarationRef }\nfn probe(f: Fact) -> std.decl_ref.DeclarationRef { f.r }\n", "src/test_claim_qualified_type_ref_probe.rs", - ["use crate::std_determinism::{Determinism};"], - ["std.determinism.Determinism"] + ["use crate::std_decl_ref::{", "DeclarationRef};"], + ["std.decl_ref.DeclarationRef"] ) }