From 29c2a9520f6f4716cdc8f64fe876cd5eb726a258 Mon Sep 17 00:00:00 2001 From: konstin Date: Sun, 10 Aug 2025 13:18:27 +0200 Subject: [PATCH] Add method for incompatibilities between virtual and base packages Add a new method to add a single custom incompatibility that requires the base package and the proxy package share the same version range. This intended for cases where proxy packages (also known as virtual packages) are used. Without this information, pubgrub does not know that these packages have to be at the same version. In cases where the base package is already to an incompatible version, this avoids going through all versions of the proxy package. In cases where there are two incompatible proxy packages, it avoids trying versions for both of them. Both improve performance (we don't need to check all versions when there is a conflict) and error messages (report a conflict of version ranges instead of enumerating the conflicting versions). There's several usage patterns for this method. The basic one is upon encountering a dependency on a proxy package with a range, using this method with its base package and that range. --- src/internal/core.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/internal/core.rs b/src/internal/core.rs index a61eba0d..d6fd1040 100644 --- a/src/internal/core.rs +++ b/src/internal/core.rs @@ -96,6 +96,38 @@ impl State { self.merge_incompatibility(id); } + /// Add a single custom incompatibility that requires the base package and the proxy package + /// share the same version range. + /// + /// This intended for cases where proxy packages (also known as virtual packages) are used. + /// Without this information, pubgrub does not know that these packages have to be at the same + /// version. In cases where the base package is already to an incompatible version, this avoids + /// going through all versions of the proxy package. In cases where there are two incompatible + /// proxy packages, it avoids trying versions for both of them. Both improve performance (we + /// don't need to check all versions when there is a conflict) and error messages (report a + /// conflict of version ranges instead of enumerating the conflicting versions). + /// + /// Using this method requires that each version of the proxy package depends on the exact + /// version of the base package. + pub fn add_proxy_package( + &mut self, + proxy_package: Id, + base_package: Id, + versions: DP::VS, + ) { + let incompat = Incompatibility::from_dependency( + proxy_package, + versions.clone(), + (base_package, versions), + ); + let id = self + .incompatibility_store + .alloc_iter([incompat].into_iter()); + for id in IncompDpId::::range_to_iter(id) { + self.merge_incompatibility(id); + } + } + /// Add an incompatibility to the state. #[cold] pub(crate) fn add_incompatibility_from_dependencies(