Borrow-accessor groundwork: syntax, statics, and epoch-engine inlining (ADR-0062 phases 0–1) - #2077
Merged
Merged
Conversation
steveklabnik
marked this pull request as ready for review
July 29, 2026 15:30
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Jul 29, 2026
steveklabnik
enabled auto-merge
July 29, 2026 15:36
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Jul 29, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Jul 29, 2026
github-merge-queue
Bot
removed this pull request from the merge queue due to a conflict with the base branch
Jul 29, 2026
…och-engine inlining Place-returning borrow accessors (ADR-0062, S2 surface) through the epoch semantic engine, behind the borrow_accessors preview gate: - yield keyword; -> borrow T result position on fn/method declarations (grammar-side only; free functions are rejected in sema, E0257) - RIR: FnDecl.returns_borrow and InstData::Yield - Sema statics: the (Accessor-Call) rule as an expression-scoped shared loan on the receiver root (ctx.expression_loans, truncated per full expression) checked against inout loans, moves, and assignments (E0259); dedicated escape diagnostics for return/store/let/capture (E0250-E0253); accessor-body well-formedness (single trailing yield, receiver-rooted place; E0254-E0256); declaration shape checks (borrow self receiver, by-value params; E0257, E0260); drop-glue value reads out of a result rejected (E0258); everything behind require_preview(borrow_accessors) (E1100 when off) - Mandatory inlining at call sites in the shared body engine: an accessor call expands to its guards plus the yielded place, traced as a caller-rooted PlaceTrace (no call emitted, no ABI); the standalone accessor compiles its guards plus an unreachable trap so downstream stages see no new shapes - Accessor-body inference runs on demand at expansion and overlays the caller's resolved types - rue-air unit coverage for inlining, gating, every escape shape, exclusivity conflict, and body well-formedness Known limitation, detailed in the PR: the incremental provider body path prunes callee declarations from each body request's RIR, so call-site expansion cannot see accessor bodies there; completing the feature needs body-input changes in the query nucleus, which this change deliberately does not touch. Toward RUE-662. Part of RUE-1015.
…erage Pull the documentation and coverage deliverables forward while the provider-eligibility fallback waits on RUE-1033: - Add spec chapter 6.6 (Borrow Accessors) with rules 6.6:1-6.6:13, the `yield` keyword row in 2.4:2, and `result`/`yield_expr` grammar productions in appendix A. - Amend the formal core with the (Accessor-Call) rule, accessor body well-formedness, and the inlined-call dynamics note in section 5.8, plus the section 8 traceability row. - Add spec cases for chapter 6.6: declaration/body rules and the guard-trap dynamics case pass through today's driver and are required coverage; the remaining call-site cases (escapes, exclusivity, drop-glue read, in-place execution) run as preview-allowed-to-fail until the eligibility change lands, with matching KNOWN_UNCOVERED_NORMATIVE entries for 6.6:8-6.6:11. - Re-check the accessor declaration shape (E0257 receiver, E0260 parameter modes) in the shared body engine so those rules hold on every analysis host, including the incremental driver. - Point the ADR-0062 frontmatter at the `borrow_accessors` feature name. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RwaF7SFHXcBuKdYrnwi5G
The oracle-diff audit classifies a spec case's expected trap from its runtime_error string, and "index out of bounds" names the built-in IndexOutOfBounds trap — but the accessor's guard is spelled @Panic("index out of bounds"), which traps as UserPanic. Use the established user-panic assertion shape (exit_code = 101 with stderr_contains = "panic: ...") so the expected trap kind matches the one the program actually raises. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015RwaF7SFHXcBuKdYrnwi5G
steveklabnik
force-pushed
the
steve/rue-662-borrow-accessors
branch
from
July 29, 2026 15:52
9f91a33 to
da6a9dc
Compare
steveklabnik
enabled auto-merge
July 29, 2026 15:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Toward RUE-662. Part of RUE-1015. Refs RUE-1016, RUE-1017.
Scope note: this lands the phase-1 groundwork — syntax, statics, epoch-engine inlining, formal core, spec chapter, and all coverage that runs through today's driver. One follow-up remains before RUE-662's acceptance criteria close: the provider-eligibility fallback, which per the maintainer ruling (recorded below) waits for RUE-1033 to land before touching engine eligibility. Deliberately uses no closing keyword until that follow-up completes the issue.
What this implements (ADR-0062, S2 surface, all behind
--preview borrow_accessors)yieldkeyword (lexer + spec-visible token names);-> borrow Tresult position onfn/method declarations (Function.borrow_return/Method.borrow_returnin the AST,FnDecl.returns_borrowin RIR); aYieldRIR instruction; lowering, printing, validation, remapping, and frontend-diff/artifact-view arms.(root(receiver), shared)loan whose extent is the enclosing full expression, tracked in a newexpression_loanscontext set that the statement loop truncates per full expression. Exclusive uses inside that extent —inoutarguments/receivers, moves, assignments — are rejected with the new E0259 (use(v.get_ref(i), g(inout v))is the canonical rejection, covered by a unit test). Escape shapes get dedicated diagnostics: return E0250, store E0251, plainletE0252, aggregate capture E0253. Accessor bodies are well-formed iff every non-diverging path falls through to the single trailingyieldof a place rooted at the receiver (E0254/E0255;return/?in a body and strayyieldare rejected, E0256). Declarations require aborrow selfreceiver and by-value, trivially-shaped parameters (E0257/E0260) — re-checked in the shared body engine so they hold on every analysis host, including the incremental driver; reading a drop-glue value out of a result by value is E0258 (the RUE-651 aliasing-owner hole stays closed). Everything gates throughrequire_preview()(E1100).yieldrow in the 2.4:2 keyword table, andresult/yield_exprproductions in appendix A. Spec cases cover every declaration/body rule, the preview gate, and the guard-trap dynamics as required coverage through today's driver; the remaining call-site cases (escapes, exclusivity, drop-glue read, in-place execution) are written and run as preview-allowed-to-fail, with matchingKNOWN_UNCOVERED_NORMATIVEentries for 6.6:8–6.6:11 that the traceability gate will force us to retire when the cases flip.rue-airunit tests exercise the inline expansion (noCallin the caller's AIR, guards present), the preview gate, every escape shape, the exclusivity conflict, and each body/declaration well-formedness rejection.Driver status and the recorded ruling
The production driver analyzes bodies through the incremental provider path (
ProviderBodyHostover the semantic query nucleus). Each body request receives a pruned, re-lowered RIR containing only that body — no struct declarations, no callee method bodies — so call-site inlining cannot happen on that path today: the call site can't learn the method is an accessor (the durableCallableSignature/DurableMethodschema doesn't carryreturns_borrow), and the callee's guards/yield RIR isn't present to splice. Body-level diagnostics (gating, declaration shape,yieldplacement, rooting) do fire through the driver; the epoch engine implements the full semantics.Maintainer ruling (2026-07-29): the epoch-engine fallback is approved as bounded preview scaffolding for RUE-662 — "a program that declares any accessor routes to the epoch engine" — with the CFG-threshold splice as the production mechanism and a hard prerequisite for RUE-1017 (tracked as RUE-1208, blocking RUE-1017). Sequencing: let RUE-1033 finish before touching provider eligibility, then land the eligibility change with a focused epoch/provider parity test demonstrating the fallback is intentional, flip the deferred spec cases to required coverage, retire the known-uncovered entries, and add the UI/CLI call-site coverage.
Also disclosed: two compile-forced mechanical edits in
crates/rue-compiler(artifact_views.rs,parsed_modules.rs) — exhaustive-match arms for the newYieldAST/RIR variants; no query or session logic was touched.Not included
The provider-eligibility change described above (waiting on RUE-1033), the CFG-threshold splice (RUE-1208), mutable accessors (RUE-1016), and std adoption (RUE-1017).
Testing
scripts/rue quick(30/30 targets), full spec suite (2211 passed, deferred accessor call-site cases running as preview-allowed-to-fail), the spec traceability gate, the full UI suite (209/209), and the oracle-diff spec corpus audit all pass; the tree builds clean across all crates.Generated by Claude Code