Skip to content

fix: keep anonymous field receivers alive - #15

Merged
fullofcaffeine merged 3 commits into
mainfrom
fix/dnt5-optional-field-borrow
Aug 31, 2026
Merged

fullofcaffeine merged 3 commits into
mainfrom
fix/dnt5-optional-field-borrow

Conversation

@fullofcaffeine

Copy link
Copy Markdown
Owner

Outcome

Valid typed Haxe can now read an optional anonymous-record field through a temporary record handle. Generated Rust keeps that handle alive until the read guard ends, so rustc no longer reports E0716.

Cause and fix

A class field read can produce a temporary cloned record handle. Optional-field lowering then stored a read guard from temporary.borrow() in a generated local. Rust dropped the temporary before the guard reached its final use.

The compiler now uses one structural receiver check for instance and anonymous fields. When an optional or function-valued field read has a temporary receiver, lowering binds the receiver and the owned result. Stable receivers and direct required-field reads retain their existing output.

This is compiler-only lowering. It adds no runtime helper and no application-specific rule.

Contract-first evidence

The framework-neutral anon_optional_field_from_class snapshot covers:

  • a class-owned typed anonymous record;
  • an omitted optional string field;
  • a present optional string field;
  • Haxe interpreter behavior;
  • generated Rust formatting and compilation;
  • the generated receiver, guard, and result lifetimes.

Before the fix, Cargo failed with error[E0716]: temporary value dropped while borrowed in the generated class method.

Validation

Passed locally on this exact head:

  • Haxe interpreter run for anon_optional_field_from_class
  • bash test/run-snapshots.sh --case anon_optional_field_from_class --update
  • bash test/run-snapshots.sh --case anon_optional_field_from_class
  • bash test/run-snapshots.sh --case anon_optional_fields
  • bash test/run-snapshots.sh --case anon_required_field_types
  • generated Rust inspection for intended/src/holder.rs
  • npm run hooks:check
  • git diff --check

Hosted CI remains the broad snapshot, Clippy, standard-library, package, template, and example proof. The independent codex-hxrust consumer replay remains deferred until review selects a merge candidate.

Documentation

The compiler guidance and v1 behavior reference now describe the receiver lifetime rule. README and FAQ need no separate change because this patch adds no syntax, API, or user workflow.

Agent provenance

Prepared by the haxe_rust-dnt5 compiler agent after the consumer project isolated a generic E0716 compiler failure. This agent owns review fixes and rebasing for this draft branch. The repository maintainer owns final approval and merge. Other agents must review or comment without changing this branch unless the maintainer records a handoff.

No independent reviewer has approved this head yet. Hosted CI and maintainer review remain required before merge.

@fullofcaffeine

Copy link
Copy Markdown
Owner Author

Independent reviewer note: semantic review is GO on head 4cd609d19605fed81b8296277d788c8f209e51c2, conditional on hosted CI and exact landed-commit consumer replay. The change is narrowly owned: only optional or function-valued anonymous-field reads with unstable receivers gain a local lifetime binding; stable receivers and required direct reads retain their prior lowering. The framework-neutral fixture reproduces the original E0716 shape and the generated holder.rs keeps the receiver alive until the owned result leaves the guard scope. No application-specific rule or runtime helper was added. Reviewer role: primary cross-repository integration agent. Final approval and merge remain with the repository maintainer.

@fullofcaffeine

Copy link
Copy Markdown
Owner Author

CI follow-up on head 281cef5958a19ab1574198bded78275bc0bf63c6:

Both snapshot jobs stopped before compiling snapshots. The compiler edit shifted one reviewed raw-authority call site from line 17301 to 17332, while the generated inventory still named the old line. The exact CI snapshot command reproduced the stale-inventory assertion locally.

Commit 281cef59 refreshes only that generated line record. The authority ID, enclosing function, factory, and approved owner remain unchanged. npm run test:rust-raw-authority now passes, including the hello_trace generated Rust build. A fresh hosted CI run is in progress.

The haxe_rust-dnt5 compiler agent retains ownership of review fixes and rebasing. The repository maintainer retains final approval and merge ownership.

@fullofcaffeine

Copy link
Copy Markdown
Owner Author

Snapshot follow-up on head 74c461dcb14c1f15ed49364cef87b798a42be931:

The refreshed hosted shard passed the stale raw-authority gate and then found one expected-output difference in haxe_crypto_smoke. Haxe Unserializer reads function-valued resolveClass and resolveEnum fields through a temporary resolver handle. Those six generated reads now use the same intended receiver and owned-result scope as the new regression.

This was a legitimate adjacent golden-output update. The callback value remains cloned before invocation, and the read guard ends before user code runs. Commit 74c461dc updates only test/snapshot/haxe_crypto_smoke/intended/src/haxe_unserializer.rs.

Focused validation passed:

  • bash test/run-snapshots.sh --case haxe_crypto_smoke
  • bash test/run-snapshots.sh --case anon_optional_field_from_class
  • npm run test:rust-raw-authority
  • git diff --check

The PR remains draft. The haxe_rust-dnt5 compiler agent retains review-fix and rebase ownership. The repository maintainer retains final approval and merge ownership.

@fullofcaffeine

Copy link
Copy Markdown
Owner Author

Independent reviewer update on exact head 74c461dcb14c1f15ed49364cef87b798a42be931: semantic review remains GO, conditional on hosted CI and post-PR-#16 rebase/revalidation. The raw-authority update changes only the generated source line for the same reviewed factory and owner. The haxe_crypto_smoke expected diff is a legitimate adjacent consequence: function-valued resolveClass/resolveEnum reads now bind the temporary anonymous receiver, clone the callable while the guard is held, and invoke only after the guard scope ends. No additional production behavior changed. Reviewer role: primary cross-repository integration agent. Final approval and merge remain with the repository maintainer.

Optional anonymous-field reads used to borrow directly from a temporary record handle. Rust dropped that handle before the generated read guard, so valid typed Haxe failed with E0716.

The compiler now binds temporary receivers and the owned field result when a read needs a scoped guard. Stable receivers and direct required-field reads keep their existing output.

A framework-neutral snapshot covers a class-owned record with missing and present optional values. Focused interpreter and generated Rust checks pass, along with the repository hook guards. Full harness and independent consumer validation remain for hosted review.
The shared receiver-lifetime rule also changes generated Haxe Unserializer callback reads. Each temporary resolver handle now stays alive until the callback value is cloned and its read guard ends.

This updates only the affected expected Rust. Focused haxe_crypto_smoke, optional-field, and raw-authority checks pass.
The merged compiler baseline moved the raw Rust call site and added one snapshot case. Regenerate the tracked inventories from that exact baseline so the branch remains reviewable after rebasing.

Verified with the focused optional-field and haxe crypto snapshots, the raw-authority guard, and the repository hook checks. No compiler behavior changes are included in this commit.
@fullofcaffeine
fullofcaffeine force-pushed the fix/dnt5-optional-field-borrow branch from 74c461d to e8cc4b3 Compare August 31, 2026 12:08
@fullofcaffeine

Copy link
Copy Markdown
Owner Author

Rebase update (compiler task haxe_rust-dnt5):\n\n- Rebasing owner: the compiler-task agent.\n- Review and merge owner: the repository maintainer.\n- New base: 6dbb6c32365cc41ac6c529d449ee1f166d5bd4ff (merged PR #16).\n- New head: e8cc4b30a775bcc9121753526936f4164c70cca1.\n- Conflict scope: only the owned Dynamic allowlist line moved; tracked raw-authority and semantic-confidence evidence was regenerated from the new base.\n- Revalidated: anon_optional_field_from_class, haxe_crypto_smoke, npm run test:rust-raw-authority, and npm run hooks:check. Generated Rust retains the owned-value scope that prevents borrowing from a temporary.\n\nThe draft remains unmerged. A combined consumer vertical-tracer rerun is deferred because the shared consumer checkout changed during coordination; no consumer result is claimed in this update.

@fullofcaffeine

Copy link
Copy Markdown
Owner Author

Combined consumer admission on exact rebased head e8cc4b30a775bcc9121753526936f4164c70cca1 is green. A clean/head-enforced codex-hxrust run passed the authored interpreter observer, metal generation, locked Cargo check/test, rustfmt, warning-denied Clippy, generated binary, session shutdown, and terminal restoration. Generated review confirms the original call now emits HxDynRef::new(transport.clone()) and the optional startup request field binds __hx_recv before borrowing. This is pre-merge evidence only: upstream reachability correctly remains false until merge, and exact landed-commit replay plus pin admission are still required. Reviewer role: primary cross-repository integration agent.

@fullofcaffeine
fullofcaffeine marked this pull request as ready for review August 31, 2026 13:07
@fullofcaffeine
fullofcaffeine merged commit 02b21f9 into main Aug 31, 2026
25 checks passed
@fullofcaffeine
fullofcaffeine deleted the fix/dnt5-optional-field-borrow branch August 31, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant