Analysis: Follow state through a block parameter - #2288
Merged
Conversation
|
View your CI Pipeline Execution ↗ for commit af3768c
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗ ☁️ Nx Cloud last updated this comment at |
marcoroth
force-pushed
the
analysis/rust-block-aliases
branch
from
August 18, 2026 23:47
af3768c to
b337dfe
Compare
🌿 Interactive Playground and Documentation PreviewA preview deployment has been built for this pull request. Try out the changes live in the interactive playground: 🌱 Grown from commit ✅ Preview deployment has been cleaned up. |
commit: |
marcoroth
added a commit
that referenced
this pull request
Aug 19, 2026
This pull request teaches the dependency analysis that a local assigned from a piece of state carries that state. ```erb <% total = @items.size %> <p><%= total %></p> ``` `total` is `@items`, counted. Matching is by name, so nothing connected the two and `total` was attributed to nothing, which meant `herb dependencies` and `herb actionview flow` left the paragraph out of what `@items` reaches. Follow up on #2288, which did the same for the names a block binds. This is the other way a state gets a second name. An assignment binds the name only when its right hand side reads the state, and the name carries it for as long as the assignment is in scope. ```erb <% a = @items.size %> <% b = a * 2 %> <p><%= b %></p> ``` `a` carries `@items` and `b` carries `a`, so `b` reaches back to `@items` through the chain. Three cases that look like assignments and are not: - `<% other = 5 %>` binds nothing, because nothing on the right reads the state. - `<% if total == @items.size %>` is a comparison, and `total` is left alone. - A local assigned inside a block stops carrying at the end of that block, the same rule the block parameters follow.
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.
This pull request teaches the dependency analysis that a block's parameters carry whatever that block iterates, in one template and across a
rendercall, and in all three languages that implement it.itemis@items, one at a time. Matching is by name, so nothing connected the two, anditem.namewas attributed to nothing.Ruby learned this within a single template in #2280. This finishes it: the two ports learn the same thing, and the Ruby trace learns it across a render boundary, which is where it was answering a user-facing question incorrectly.
affected_templatesandstate_flowbackherb dependenciesandherb actionview flow, and their whole product is the list of templates a piece of state reaches. One shape was missing from it.traced:
not traced:
For the second,
affected_templates(entry, "@posts")returned["index.html.erb"]and omitted_card.html.erb, andstate_flowreturned a tree with no child.trace_stateasks whether a render call's local carries the state, andcard: postnames a block parameter that nothing tied to the collection that bound it.The collector now records the blocks open around a render call, with the names each binds, and a local whose value is one of those names carries what its block iterates.
analyzenow parses withiteration_nodes, so a block running per item and a block running once are different node types. Without that,form_with model: @post do |f|looks like a collection andfcarries@postinto every partial rendered inside the form.Once the trace reaches
_card.html.erb, its slots become addressable, and they came back as anidentity, which is a client writing one value into every card. A render inside an iterating block is now per item the same waycollection:is, and the modes below a block that runs once are left alone.Follow up on #2279, #2280, #2281, #2282 and #2283.