Repository navigation
fix: share inert-region handling and preserve Elixir unquote calls (#357) - #380
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configuration
⛔ Files ignored due to path filters (2)
📒 Files selected for processing (21)
Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughElixir ingestion now distinguishes inert quote syntax from enabled ChangesElixir quote semantics and capture
Priority: ⬇️ Low Estimated code review effort: 3 (Moderate) | ~25 minutes Change: Bug fix Suggested reviewers: Merge Risk: ⚪ Minimal · up to No merge-blocking issue is established for this change; it is ready for normal merge checks. 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
|
@LaimaWu this looks great, we are in a couple day delay/holding pattern from using a lot of tokens this weekend (~8 branches of nice improvements almost delivered), get more tokens Wednesday morning... |
|
Thanks @LaimaWu — this is a lovely first PR: red-first on One housekeeping note: CI hasn't run on this branch yet because GitHub holds workflow runs from a new contributor's fork until a maintainer approves them. That's on our side, not yours, and we'll get it approved. |
|
Thanks again @LaimaWu, and sorry this review took longer than we said it would. We've now been through it carefully, and it's a strong change. Here's what we checked:
Folding it in.
The merged tree builds. On the merged binary, the Elixir gates, A few things we found. None of them blocks the merge. If you'd like to take the first one, a small commit on this branch would be welcome; otherwise we'll fold it into the train:
One follow-up we'll take on ourselves, outside this PR's scope: a function that is called only from inside a Thanks for the careful red-first commits and the clear write-up. They made this straightforward to review. |
…ner waiver) Owner waiver 2026-10-16: the ten shared-file Lang:: predicates came from lanes signed before #399's ratchet (grep-carrier +1, ruby-pair +4, qd-memory-degrade +1, #380 +1, attrib-multidef/declined-sites +3), so the ceiling moves 352 -> 362 once, recorded as a dated, named exception beside the unchanged never-rise rule. Train 29 brings it back to <= 352. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Train 28: --for stops when complete + owner body, per-definition attribution, declined-call rows, git child hardening, #380
kParserVer and its mirror 176 (rich file tag 177): above main's 173/174 and every lane build (grep-carrier 173, ruby-pair 174/175, PR redhat-et#380 145, the rest 171). kCacheVersion and its mirror 31 -> 32: RefRole gained Subscript (9) and Inert (10, 9 on the PR's branch). kQSnapCacheScheme 20 -> 21: the dead set's call inputs moved. qschemetrip.hash re-derived once with a RE-PIN LOG entry. CHANGELOG: the versions paragraph, the entries that stated a branch number, and an entry for PR redhat-et#380 (closes redhat-et#357), which carried none. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stacked on attrib-multidef. Conflicts: src/verbs_navigate.h — the callees legend takes the lane's rows-aware declinedCallsLegendForRows; PR redhat-et#380's inert clause rides it through a new trailing parameter (src/graphlegend.h), in the same place declinedCallsLegendWithGates puts it, with or without <dc> rows (the inert quote sites reach no decline site, so they never have a row). CHANGELOG.md (all entries), test/regression.sh (union), generated docs (main's side; regenerated at the train). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…es no longer aborts on one Merge interaction (PR redhat-et#380 x lane declined-sites): redhat-et#380 counts an Elixir call candidate inside inert quote AST in declinedOut, but it reaches no decline site, so it writes no declinedSite* record; declinedSitesMadeBy's postcondition (records == declined_calls=) then aborted --callees on such a function, e.g. `ripwire test/elixirfix --callees=quoted`. Graph::inertDeclinedCaller keeps each inert site's caller, and both postconditions count it (records + inert sites == declined_calls=). Beside <dc> rows, the inert clause now adds that no row names those quoted sites. Gate: declinedsitecheck (L) — red on the merged binary before this commit (exit -5 twice, the sentence missing). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…Rust, C++ and Go Two maintainer paragraphs under "Adding a language: common stays common", before the feature families: the three homes of language-specific code (facts, hooks, family rows) and the Rust/C++/Go call for contributions, with **wanted** beside the slices it names (1a and 2b for Rust, 4c and 7a for Go, 11a for Rust). Row 8 now says the shared inert-region walk landed with redhat-et#380 and that slice 8a (Clojure onto it) is ready. "Before you ask for review" gains items 22 (a zero-hit word stays out of what the repository indexes) and 23 (a new rule that repeats a reviewed helper reuses it). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d, and only there CR pre-pass (PR redhat-et#380 x lane declined-sites), three surfaces: - The MCP analyze and rank_by maps counted the inert quoted sites in declined= without their clause (serialize's trailing argument defaulted to 0); they now pass Graph::inertDeclinedCalls as the CLI map does. - The callees legend charged the inert sentences graph-wide, so an answer whose every declined call has its <dc> row still said some had none. They now ride only where the selector's own definitions made an inert site (inertDeclinedMadeBy, which returns at once on a tree with no quote). - The MCP declined_note's of_def, cut and candidates clauses speak the entry keys too (of_def [K] / [K~d], dc_shown / dc_next, candidates). Gate: declinedsitecheck (L) l_rows_legend (a selector with both), l_rows_no_inert, l_mcp_map and (M) m_mcp_note_ofdef — the last three red on the merged binary before this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Closes #357.
Problem
Quoted Elixir AST should not produce call edges. Evaluated
unquote/unquote_splicingarguments should. Main suppresses both and silently drops quoted call candidates from declined accounting.Red-first reproduction
The expanded existing
elixircheck.shfails on upstream255dc199withunquote(bar(x)) lost its live call edge. A preserved fixture moves from 3 edges / 0 declined to 7 edges / 4 declined; removing its four inert sites moves the declined count by four. Negative controls and red cases cover nested quotes, quote options, declaration/metadata holes, quoted module scope, operator/capture counting and a C++ CDATA marker collision.Root cause
elixirQuotedtreated every quote ancestor as inert. It did not distinguish the quote body from evaluated options or live holes. Declaration/pattern filters and module lookup also followed quoted ancestors into evaluated arguments.Implementation
A small shared ancestor walker classifies inert boundaries and live holes through an Elixir adapter. Capture extraction and lexical context use the same decision. Current query predicates are not evaluated, and Elixir special forms use ordinary call nodes; inert/live query captures would still need the same target/body classification in C++. The shared hook fits that architecture. No #374 hook-table refactor.
Live-hole semantics
An enabled hole consumes one enclosing quote boundary; walking continues through outer boundaries. A quote nested inside a live hole becomes inert again. Quote option expressions remain live.
bind_quoteddisables holes by default; literalunquote: trueenables them, while false/unknown values remain conservative. Live arguments retain their real lexical module and bypass outer quoted heads/metadata. Ordinary functions namedquote/comment, and calls after the region, stay live.Counted, not dropped
Captured inert ordinary calls, operators and named captures persist as
RefRole::Inert. Graph building records existingDeclined/ callerdeclinedOutaccounting without edges or target candidates.declined=anddeclined_calls=expose those sites with conditional full/compact explanations. Bare variable-shaped AST does not inflate the count; inert sites create no uses, possible-caller or impact candidates.Validation and byte identity
Validated final SHA b479b4f against pristine main 255dc19 on macOS, with clean development, G1 and Release/LTO builds.
oswin32logiccheckfails in libc++23's intentional integer conversion, also reproduced on pristine main; its separate platform-compiler rerun, including sanitizer and mutant controls, passes. The separately scopededitchecknotecheckreference-binary rerun passes. Other skips are the optionalargvdiffcheckreference, the unavailable map-section arm and the Apple Silicon portable-build arm on this Intel host.--clonescontrols include ripwire (total=641) and the vendored tree-sitter runtime snapshot (total=26); C/C++ grammar snapshots have zero clones and serve as additional controls. Existing golden bytes are unchanged.--no-cache.Local baseline failure: On this macOS host, memguardcheck B8/B8b fail on both pristine upstream main (255dc19) and this branch: both correctly terminate with rc=5 and no answer, but the real 64M hard-limit reading fires at graph build rather than at the ingest phase asserted by the gate. The four controlled calls use the same compiler, build type, machine, fixture and commands: rc=5, stdout=0 bytes, phase=graph build, and complete stderr is byte-identical. No memory-guard code was changed in this PR. All #357-specific gates and all other non-baseline required gates pass. B8/B8b are not described as passing.
The complete suite uses the documented CI-default environment (optional historical reference-binary variables unset); raw comparison and scoped reference checks are recorded separately.
Clojure / #349 boundary
#349 has not landed. Clojure quote/discard/comment integration remains a follow-up after it lands, as accepted in #357. This PR implements only #357's Elixir arm. Associated optimization-file registration and shifted navigation captures/generated reference are updated separately.
Parser pin
Main uses 143 lean / 144 rich. This branch uses the next free temporary parser value 145 and its quality mirror: train renumbers. Cache 28 / quality scheme 17 remain unchanged; the extraction hash is re-pinned separately.
Summary by CodeRabbit
unquoteexpressions from inert quoted code, preserving call relationships only for evaluated expressions.