Skip to content

refactor(resolver): move yank policy to resolver layer #17083

Open
weihanglo wants to merge 7 commits into
rust-lang:masterfrom
weihanglo:yanked-refactor
Open

refactor(resolver): move yank policy to resolver layer #17083
weihanglo wants to merge 7 commits into
rust-lang:masterfrom
weihanglo:yanked-refactor

Conversation

@weihanglo

@weihanglo weihanglo commented Jun 7, 2026

Copy link
Copy Markdown
Member

What does this PR try to resolve?

This PR moves move yank policy to resolver layer from source layer.

We mostly preserve the old Source::query behavior that filter out yanked by default.

The yanking policy logic doesn't go into VersionPreferences or sort_summaries yet because

  • We want to minimize the refactor change. Changing the order of query and filter may change existing diagnostics
  • [replace] resolution should not see yanked candidates either
  • A future VersionPreferences predicate may still need to be invoked at this same point.

cc #17012, #17014 (comment)

How to test and review this PR?

Three tests are added to pin down more existing tests, along with #17082

Here is the list of all call site I audit:

Call site Yanked versions handling
core/resolver/dep_cache.rs query Filter
core/resolver/dep_cache.rs [replace] override Filter
core/registry.rs patch collection Filter
core/registry.rs query_overrides Filter
core/registry.rs summary_for_patch unlocked-retry Filter
core/registry.rs summary_for_patch name-only diagnostic Filter
core/resolver/errors.rs alt_versions Filter
core/resolver/errors.rs rejected_versions Keep
core/resolver/errors.rs alt_names Keep
ops/common_for_install_and_uninstall.rs select_dep_pkg (x2) Filter
ops/cargo_update.rs upgrade_dependency Filter
ops/cargo_update.rs report_latest (x4) Filter
ops/cargo_add/mod.rs get_latest_dependency Filter
ops/cargo_add/mod.rs select_package Filter
ops/cargo_add/mod.rs populate_available_features Filter
ops/registry/info/mod.rs query_summaries Filter
ops/registry/publish.rs poll_one_package Filter
ops/registry/publish.rs verify_unpublished Filter
core/compiler/future_incompat.rs get_updates Filter
crates/xtask-bump-check/src/xtask.rs check Filter

Error message is not helpful here because `source::query` has filtered
out yanked versions. Later install didn't know how to recover from that.
Only exact requirement has informative error message.

This will be improved when moving yanked version handling to resolver
@rustbot

rustbot commented Jun 7, 2026

Copy link
Copy Markdown
Collaborator

r? @epage

rustbot has assigned @epage.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

Why was this reviewer chosen?

The reviewer was selected based on:

  • Owners of files modified in this PR: @ehuss, @epage, @weihanglo
  • @ehuss, @epage, @weihanglo expanded to ehuss, epage, weihanglo
  • Random selection from ehuss, epage

@rustbot rustbot added A-dependency-resolution Area: dependency resolution and the resolver A-directory-source Area: directory sources (vendoring) A-future-incompat Area: future incompatible reporting A-git Area: anything dealing with git A-infrastructure Area: infrastructure around the cargo repo, ci, releases, etc. A-interacts-with-crates.io Area: interaction with registries A-overrides Area: general issues with overriding dependencies (patch, replace, paths) A-registries Area: registries A-source-replacement Area: [source] replacement Command-add Command-info Command-update S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 7, 2026
false
};
if is_yanked {
// Let's see if there is any yanked version so can give a more concrete error.

@weihanglo weihanglo Jun 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This showcases where this refactor could be useful.

View changes since the review

let summaries = crate::util::block_on(source.query_vec(&query, QueryKind::Exact))?;
let available = summaries.iter().any(|s| !s.as_summary().is_yanked());
Ok(available)
Ok(!summaries.is_empty())

@weihanglo weihanglo Jun 7, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This showcases where this refactor could be useful.

View changes since the review

/// Available for consideration
Candidate(Summary),
/// Yanked within its registry
Yanked(Summary),

@epage epage Jun 8, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm hesitant about dropping this. Having it as an enum ensures explicit acknowledgement rather than hoping callers know to check this.

View changes since the review

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can keep this, though I wonder how we envision on IndexSummary evolution. Do we want to have variant like IndexSummary::TooNew for min-publish-age? It was done in #17012. Or we treat yanked a bit special but not others.

Actually having IndexSummary::TooNew may help as we can flag those at registry level, and apply the policy at resolver level. What do you think?

explicit acknowledgement rather than hoping callers know to check this.

Caller still need to manually check because we have IndexSummary::{as_summary, into_summary} providing a error-prone API bypassing it. And they are all over the places we call Summary::is_yanked in this PR.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything we can do to help in this situation?

What is your read on how worth it this has been in the end?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I experimented a branch removing as_summary and into_summary. It was noisy. Some call sites only need something like s.as_summary().version() and maybe for that we should expose IndexSummary::version. Or maybe Invalid/Unsupported/Offline should be folded into one Unavailable and have their sub-enum.

Actually having IndexSummary::TooNew may help as we can flag those at registry level, and apply the policy at resolver level. What do you think?

This may look weird, as IndexSummary::parse currently doesn't have any registry specific logic. If we construct IndexSummary::TooNew there we need to thread registry config into. If we don't, we need to remap IndexSummary during query just like how IndexSummary::Offline is doing now.

On the other hand, the current change (removing IndexSummary:Yanked) is also weird because it pushes the yanked field down to Summary which is shared with git/path packages as well, and they don't have the concept of yanking.

I don't have a good answer to it though, maybe we can start with not removing IndexSummary::Yanked and see what we can do next?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done the refactor. I plan to remove into_summary and as_summary in follow-up.

weihanglo added 3 commits June 9, 2026 23:52
Since this is a refactor, 
we preserve the old `Source::query` behavior that filter out yanked by
default. Some queries actually can live without filter to get better
diagnostics, though those will be in follow-up fixes.

Here is the list of all call site I audit:

| Call site | Yanked versions handling |
| --------- | ------------------------ |
| [`core/resolver/dep_cache.rs` `query`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/resolver/dep_cache.rs#L64) | Filter |
| [`core/resolver/dep_cache.rs` `[replace]` override](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/resolver/dep_cache.rs#L91) | Filter |
| [`core/registry.rs` `patch` collection](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/registry.rs#L383) | Filter |
| [`core/registry.rs` `query_overrides`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/registry.rs#L553) | Filter |
| [`core/registry.rs` `summary_for_patch` unlocked-retry](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/registry.rs#L965) | Filter |
| [`core/registry.rs` `summary_for_patch` name-only diagnostic](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/registry.rs#L998) | Filter |
| [`core/resolver/errors.rs` `alt_versions`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/resolver/errors.rs#L432) | Filter |
| [`core/resolver/errors.rs` `rejected_versions`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/resolver/errors.rs#L450) | Keep |
| [`core/resolver/errors.rs` `alt_names`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/resolver/errors.rs#L469) | Keep |
| [`ops/common_for_install_and_uninstall.rs` `select_dep_pkg` (x2)](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/common_for_install_and_uninstall.rs#L611) | Filter |
| [`ops/cargo_update.rs` `upgrade_dependency`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/cargo_update.rs#L373) | Filter |
| [`ops/cargo_update.rs` `report_latest` (x4)](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/cargo_update.rs#L791) | Filter |
| [`ops/cargo_add/mod.rs` `get_latest_dependency`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/cargo_add/mod.rs#L823) | Filter |
| [`ops/cargo_add/mod.rs` `select_package`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/cargo_add/mod.rs#L952) | Filter |
| [`ops/cargo_add/mod.rs` `populate_available_features`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/cargo_add/mod.rs#L1180) | Filter |
| [`ops/registry/info/mod.rs` `query_summaries`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/registry/info/mod.rs#L215) | Filter |
| [`ops/registry/publish.rs` `poll_one_package`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/registry/publish.rs#L439) | Filter |
| [`ops/registry/publish.rs` `verify_unpublished`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/ops/registry/publish.rs#L451) | Filter |
| [`core/compiler/future_incompat.rs` `get_updates`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/src/cargo/core/compiler/future_incompat.rs#L334) | Filter |
| [`crates/xtask-bump-check/src/xtask.rs` `check`](https://github.com/rust-lang/cargo/blob/71b70c095bb15e278ab9f0f808397c8033079888/crates/xtask-bump-check/src/xtask.rs#L448) | Filter |

This doesn't go into `VersionPreferences` or `sort_summaries` yet because

* We want to minimize the refactor change. Changing the order of
  query and filter may change lots of diagnostics
* `[replace]` resolution should not see yanked candidates either
* A future `VersionPreferences` predicate may still need to be invoked
  at this same point.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-dependency-resolution Area: dependency resolution and the resolver A-directory-source Area: directory sources (vendoring) A-future-incompat Area: future incompatible reporting A-git Area: anything dealing with git A-infrastructure Area: infrastructure around the cargo repo, ci, releases, etc. A-interacts-with-crates.io Area: interaction with registries A-overrides Area: general issues with overriding dependencies (patch, replace, paths) A-registries Area: registries A-source-replacement Area: [source] replacement Command-add Command-info Command-update S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants