Recover from attached_packages cycles in R/ collation - #1393
Merged
Conversation
This was referenced Aug 21, 2026
thomasp85
approved these changes
Aug 24, 2026
thomasp85
left a comment
Collaborator
There was a problem hiding this comment.
LGTM - nice and surgical
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
Intent
Fixes a panic that killed the LSP main loop for a common project layout: a script in an
R/directory that callssource()on one of its collation siblings.Addresses posit-dev/positron#15631.
Approach
Salsa re-entered
File::attached_packages, found no recovery on it, and aborted withdependency graph cycle when querying File::attached_packages.The cycle comes from
R/collation, not from mutualsource(). Building a file's semantic index reads theattached_packagesof each collation predecessor, and building that predecessor's index resolves its ownsource()sites, which asks for the first file's attaches again. Three loose scripts are enough, wherea.Rsourcesb.Rand nothing sources back:Which query salsa re-enters depends on which file the editor touches first.
semantic_indexandexportsalready carrycycle_resultrecovery, so the orderings that re-enter at either of those degrade instead of crashing. The orderings that re-enter atattached_packageshad nothing to fall back to.attached_packagesandattached_packages_anywherenow carrycycle_resultrecovery as well. A file caught in the cycle contributes no attaches for the revision, so the LSP degrades instead of crashing. The recovery onattached_packages_anywhereis defensive and unreachable today, and its doc comment says so.This recovery is deliberately not the whole fix. The cycle is a false one, and the files in it already lose their attaches inside the
NoopImportsResolverrebuild that thesemantic_indexrecovery performs. Restoring those attaches means breaking the cycle structurally, which is a design change rather than a patch. I will open follow-up issues for that work and for the other cleanups this turned up.Testing
Adds
test_r_directory_collation_with_a_source_call_does_not_panic, which builds the three-script layout above and queriesc.Rfirst, since that ordering is what makes salsa re-enterattached_packages. The test fails with the recovery removed.The test asserts the degraded dependency set (
["pkgc"]) rather than the correct one. That is current behaviour, not intended behaviour, and the comment above the assertion explains the difference. When the follow-up lands, this assertion flips to all three packages.A fuzz pass over 400 random
R/directory shapes with randomsource()edges, across every entry point and target file, went from 3948 panics before the change to 0 after.Positron Release Notes
New Features
Bug Fixes
R/directory where one script callssource()on another (#15631).