A subprogram whose declined draws outnumber its trials fails by name; a dummy handed to what might write it is not read-only - #33
Merged
Conversation
… a dummy handed to what might write it is not read-only Three rows of #32 (12, 13, 14), all on main since #30 merged. * The differential gate declines a draw the candidate stops or overruns on (a translated ERROR STOP, a subscript past a dummy's extent) and one both sides take to NaN, and draws again. It did so up to 24 times per trial, counted the redraws in a per-subprogram metric nobody repeated, and passed once one draw survived -- so a translation that stopped on inputs the source accepts passed on the survivors, one at a time. Now a subprogram whose declined draws outnumber the trials it was compared on fails by name, with the count, the reason of each decline (error stop, subscript past extent, NaN on both sides) and the remedy: narrow the draw with `ranges` or pin `dims`. The reshaped rule, which names the extent, still speaks first. A passing verdict repeats the declined count and reasons in its detail; the per-subprogram metrics carry `declined` by reason beside `redrawn`. * Read-only intent inference took a parenthesised reference whose base is not one of this file's subprograms for a subscript, and never walked a function reference, an internal WRITE or an ASSOCIATE. A dummy modified through a use-associated function -- which parses exactly like a subscript -- was inferred `intent(in)`, dropped from the wrapper's outputs and compared on neither side. The pass now knows the scope's variables (dummies, locals, local parameters, module state); a base it does not name is a call whose variable actuals escape, an expression actual is a temporary and does not, and the WRITE unit and the ASSOCIATE selector escape. What cannot be proved read-only stays UNKNOWN, and the gate keeps refusing the routine by name, as it did before #30. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HYzzevwvTuLBMYjzdHUhGg
minpack's chkder takes two of the eight values the default integer range draws for mode, and was compared on the survivors: 19 draws declined against 10 trials. It is now named in the unit's detail with the reason and the remedy (pin mode with `ranges`); the unit was already failed on dogleg's moved extents. No other unit moves; the per-subprogram metrics gain `declined` by reason. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HYzzevwvTuLBMYjzdHUhGg
chenyueqi
added a commit
that referenced
this pull request
Sep 6, 2026
… and #35 The table is unchanged. Per-subprogram metrics now carry PR #31's `shaped` and `input_profile` and PR #33's `declined` by reason, and minpack's chkder is named for its declined draws as PR #33's own re-record named it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018vrAgr6x1yLT47EumS39L5
chenyueqi
added a commit
that referenced
this pull request
Sep 6, 2026
…-bounds The CLUBB stack and this branch extended the same functions in different directions; where git could not merge them, this is what was decided: - An Expr has both a `str` node (a character value) and a `call` node (a folded intrinsic); `render` spells both. Constant folding is main's typed `with_integer_division`, with the `str` short-cut kept. - One ALLOCATE scanner walks parentheses across continuation lines for both readers: an object's components (`COMPONENT_ALLOCATION`) and a module allocatable's own shape (`ALLOCATION`); `ALLOCATE_THIS` goes. - The recorder keeps this branch's guard for an array the run never allocated -- poison of the planned shape -- and generalizes it to CLUBB's case: an extent the run owns (`extent_args`, written from `size()`) is spelled zero under the guard, so `c%coef` under `sclr_dim = 0` is recorded as `(ngrdcol, 0)` of nothing, the shape the kernel's dims declare, rather than main's `(0,0)` record. `_record_component` goes; the CLUBB test asserts the new spelling. - The replay reads a logical (`T`/`F`) before it takes any other text as a character value. The flat adapter names a type only where a dummy of it is declared, and reaches a private specific through its generic. - The JAX call rewrite takes main's host-call preamble and positional list, narrowed to the emitted convention: optionals as keywords, OUT scalars omitted, an OUT array passed only where it is the caller's buffer (the `buffer` mark, not `dims`). The elided-buffer table is main's positional one with this branch's temporary for an OUT scalar the anchor unpacks; an unpassed OUT array stays refused. - The single-exit rewrite is this branch's flag-based one (returns inside loops, the guarded remainder as one block), with main's placement of the flag and placeholder after the statements before the first return, the placeholder shaped like the final value where that is already bound. The flag guard now applies at every block level through the visit of each branch, which is what main's `_fold_returns` covered (`if (bad) then; if (worse) return; y = y + 1; return`); that helper and `_guard_after_returns` go. - The kernel lowerer knows both the trace-time statics and the names that size an array or bound a range; a literal store to either stays Python. - The JAX runtime exports both sides' shims once; SUM folds sequentially along an axis too. The NumPy SUM is main's for the same reason. - `_ret`-flag tests: the statics marker may precede a loop's done flag. - Ruff and mypy on this branch's own files: long lines wrapped, a re-exported constant imported from its home, duplicate runtime definitions dropped. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018vrAgr6x1yLT47EumS39L5
chenyueqi
added a commit
that referenced
this pull request
Sep 7, 2026
…#23) The scalar half landed with PR #33; an array stayed UNKNOWN ("mutates through its buffer") and the differential gate refuses a subprogram over an UNKNOWN intent, so recast-clubb carried a table of ten array dummies with the direction their bodies give them. Written and never read is ``intent(out)`` -- when every element is: a bare name, a full section, or a subscript that is, on every axis, the variable of an enclosing DO whose bounds are to the letter the declared bounds (``do k = 1, nz; do i = 1, ngrdcol; wp4(i, k) = ...``), and not under an IF. Written in part (``lhs(i, 2:nzm-1)`` beside boundary rows, a write in one arm of an IF) or read is ``intent(inout)``: the elements the body leaves are the caller's. Only read is ``intent(in)``. A write through a subprogram of the same file counts -- an actual handed to a dummy the callee declares or was inferred to write -- and one handed to a callee's ``intent(in)`` dummy is a read, not an escape; a dummy handed to a procedure the file does not describe stays UNKNOWN. The two passes run twice so a callee's inferred intent reaches its callers. Measured: recast-clubb's ten overrides come out identical from the inference, and every one of CLUBB_core's 67 modules has the same intents with the table and without it, so the table can go with nothing to re-verify. The corpus baseline moves where it should: bspline's BLAS module, refused whole over ``dx``/``dy``, is compared now (dscal, drotmg bit-exact; the rest have their own reasons). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
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.
Closes rows 12, 13 and 14 of #32 -- the three that were on main, from #30.
Declined draws are bounded and repeated (rows 12, 13).
differential.bitexactdeclines a draw the candidate stops or overruns on (SystemExit,IndexError) and one both sides take to NaN, and draws again. It did so up to 24 times a trial, counted the redraws in a per-subprogram metric nothing repeated, and passed once one draw survived: a translation that stopped on inputs the source accepts passed on the survivors. Now:error stop,subscript past extent,NaN on both sides) and the remedy (ranges, ordims). The reshaped rule, which names the extent, still speaks first.declinedby reason besideredrawn.The whole-trial NaN redraw is kept -- what both sides do after a NaN is the compiler's scheduling -- but it is now counted against the same bound and said aloud.
Read-only is proved, not assumed (row 14).
_infer_read_only_intentstook a parenthesised reference whose base is not one of this file's subprograms for a subscript, and never walked a function reference, an internal WRITE or an ASSOCIATE; a dummy modified through a use-associated function, which parses exactly like a subscript, was inferredintent(in), dropped from the wrapper's outputs and compared on neither side. The pass now knows the scope's variables (dummies, locals, local parameters, module state): a base it does not name is a call whose variable actuals escape, an expression actual is a temporary and does not, the WRITE unit and the ASSOCIATE selector escape. What cannot be proved read-only stays UNKNOWN, and the gate refuses the routine by name, as before #30.Held to: full suite (916), mypy, ruff green. Corpus re-run: no unit moves (31/67 mechanical, 433 deferred); minpack's
chkderis now named in its unit's detail (19 draws declined, 19 error stop, against 10 trials --modetakes two of the eight default integer values), a unit already failed on dogleg's moved extents. The intent tightening moves nothing in the corpus.Tests: the redraw tests now assert the reason and the verdict's mention of it; two new ones hold the bound for an error stop and for NaN; one new interface test holds each escape (function actual, internal WRITE, ASSOCIATE) and each non-escape (array subscript, expression actual).
🤖 Generated with Claude Code
https://claude.ai/code/session_01HYzzevwvTuLBMYjzdHUhGg