Repository navigation
Emitter: an effectful fold step is realized as a loop in the enclosing async frame (native broker class E) - #13154
Conversation
…g async frame Fold handed its step to Iterator::fold as a synchronous closure, so an effectful callee's `.await?` landed inside it (rustc E0728). The step now runs as a `for` loop over a mutable accumulator when it reaches an awaited call, asked of the same two authorities that write the await (item_is_effectful_callee and is_typed_service_call_receiver). Pure folds keep the closure realization. Control: src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs emits, rustc- compiles and runs an effectful fold with a record accumulator (RED before, green after). Stage0 mirror via claim_executor --required-regen; second pass is a fixed point. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ee (required-regen; second pass is a fixed point) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
On the advisory in review 75067 (a receipt for the hand-written Rust test): The receipt is a deferral. The test exists only because the shared emitted-and-run control label On the noted limitation (a nested non-fold closure that awaits): agreed, it is not a regression. It belongs to the effectful-function-value class ( — sent from loyal-gull-749 |
briansrls
left a comment
There was a problem hiding this comment.
NO-LAND at this head, for one integration reason only. The lowering itself looks correct: effectful fold steps belong in the enclosing async frame, the pure .fold(..) arm stays unchanged, the effect test reuses the existing await authorities, and the broker delta removes the five E0728 identities without creating new ones. CI is green.
But this PR is based on 4998418, which is the merge commit of #13144. Therefore the stated deferral for src/v1/stage0/tests/effectful_fold_step_emitted_rust.rs is no longer true: //gunbc/instruments:native-emission-controls already exists on this base and is explicitly the shared authority for emitter-rule controls. Please move this effectful-fold specimen into gunbc.instruments.native_emission_controls as emitted/build/run cases with declared roster identities, delete the hand-written Rust integration test, run the shared label, and re-request. This is the same consolidation rule applied to #13137.
…ds the filesystem_io handler when the report demands it Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… main, regenerated next)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ld control into native-emission-controls and delete the hand-written test
…d-written test); stage0 mirror regenerated Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…rror taken from main, regenerated next)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Native broker wave 2D (program: gentle-dove-36), class E: an effectful call inside a fold step emitted
.await?into a synchronous closure (rustc E0728).Re-derivation (DESIGN §6b)
foldis a bounded Loop.Iterator::fold(init, |acc, x| …)is one realization of it, and that realization assumes a pure step: the closure is its own synchronous frame. The call arm decides.await?by the one effect authority (v1.compiler.infer_itemsitem_is_effectful_callee, plusis_typed_service_call_receiverfor service ops), and the enclosing fn is alreadyasyncbecause it reaches that effect. So the defect is not the await. It is the closure: an effectful step belongs in the enclosing frame, where.awaitand?mean what they mean everywhere else in the fn (an effect's refusal propagates out of the fold as it would out of alet). This is the same move as the effectful tail-call lowering (a loop over a mutable state slot in the caller's frame), applied to the Loop that fold already is.Change (
src/v1/05_emit_rust.dag,emit_rust_fold_method_call)rust_expr_reaches_awaited_callasks, over the step's subtree, exactly the two predicates that write an.await?. It mints no new effect authority.emit_rust_effectful_fold_loopemits{ let mut __fold_acc[: T] = init; for __fold_elem in iter { let acc = __fold_acc; let x = __fold_elem; __fold_acc = { body }; } __fold_acc }. The body is emitted by the ordinary expression emitter against the same lambda scope;take_ownedis applied when the closure path would apply it..fold(init, closure)realization unchanged. The closure string is now built only on that arm.rust_fold_safe_acc_type: the unit-element accumulator rule (Option<()>etc. →_) is hoisted so both realizations share it. The first probe of the loop arm annotated the rawOption<()>and producedexpected Option<String>, found Option<()>ingunbc.package_deliveryseed_npm_cache_from_admitted; sharing the rule removed it.v1_compiler_emit_rust.rscomes fromclaim_executor --required-regen(the only drift reported); the second pass is a fixed point (REGEN2_EXIT=0).Control:
//gunbc/instruments:native-emission-controls(emitted, built, RUN)The hand-written stage0 test is deleted. Per gentle-dove-36's ruling, the control lives in the shared label. Cases in
gunbc.instruments.native_emission_controls:control_tally_absent_readsfoldsFilesystem.Readover three paths under a root no host provisions, into a record accumulator (thepending_escalationsshape). Its cases areeffectful_fold_step_counts_every_refused_read(=3) and the redseffectful_fold_step_red_seen_counts_elements(=3) andeffectful_fold_step_red_empty_keeps_init(=0).EmittedCompilerBuildFailed first_error=error[E0728]: await is only allowed inside async functions and blocks. That is the broker's defect.warning_count=0under-D warnings.Depends on #13180 (the NativeClaimDriver Filesystem binding, its own PR as ruled). That branch is merged into this one rather than stacked, because a PR whose base is not
maingets no CI. Once #13180 lands, this diff reduces to the fold rule and its cases.Broker probe delta
Two arms, built and probed in one remote dispatch with the local-only 1B hoist, keyed by module and normalized message. At fd30a50 the count went 1082 → 1073 with this rule plus #13147 (disjoint files). This rule's share: −5 E0728, in
approval_decision_store(the brief's site),command_runner, andpackage_delivery×3. No new error identities. On the merged head 6be3086 the probe shows 1082. Main has moved since; the E0728 identities above are absent there too.Not covered: the remaining E0728s are a different class
gunbc.auth.approval_store_receiptstore_receipt_answer(×3, which the brief listed under class E) andgunbc.host_cli_dependencyfirst_absent_host_cli_dependencydo not await inside a fold step. They pass an effectful function value to a pure higher-order fn:slot: fn() -> EscalationSlotthunks intostore_receipt_answer_over, andcons: fn(A, T) -> Aintov2.std.algebrafold_list. The function type carries no effect, so the callee is emitted sync, and no emitter-local rule can make that right without effect-carrying function types. That is a language-layer gap, reported to gentle-dove-36 rather than patched.🤖 Generated with Claude Code