aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart-sat-resolver/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-03 21:50:54 +0900
committernsfisis <nsfisis@gmail.com>2026-05-03 21:50:54 +0900
commit177b894d7d77a5297bee3b2487ef18a0cae7a596 (patch)
treecb526ed3c35414dd6aa8a9bd05c722aa1b7239b6 /crates/mozart-sat-resolver/src
parentb8b81bb9beab64ad073af3b32969566f9ba5a038 (diff)
downloadphp-mozart-177b894d7d77a5297bee3b2487ef18a0cae7a596.tar.gz
php-mozart-177b894d7d77a5297bee3b2487ef18a0cae7a596.tar.zst
php-mozart-177b894d7d77a5297bee3b2487ef18a0cae7a596.zip
fix(resolver): expand root branch-alias and self.version replace links
Two related parity gaps surfaced by the `circular-dependency` fixture: 1. The root's `extra.branch-alias` entry was never materialized in the pool, and root-level `replace`/`provide`/`conflict` constraints written as `self.version` were forwarded verbatim. Mirror Composer's `RootAliasPackage`: resolve `self.version` against the root's declared version for the base entry, then add an extra alias entry (carrying the base links plus a duplicate link per `self.version` original retagged at the alias's version) when the root's version matches an `extra.branch-alias` key. 2. `Pool::matches_package` returned on the first link to a target name even when its constraint did not match the query, hiding any later link to the same target. With the alias above, that masked the second `replace` link tagged at the alias version. Keep iterating when target matches but constraint does not, so a later link can still satisfy.
Diffstat (limited to 'crates/mozart-sat-resolver/src')
-rw-r--r--crates/mozart-sat-resolver/src/pool.rs50
1 files changed, 27 insertions, 23 deletions
diff --git a/crates/mozart-sat-resolver/src/pool.rs b/crates/mozart-sat-resolver/src/pool.rs
index 2c52791..8a63c05 100644
--- a/crates/mozart-sat-resolver/src/pool.rs
+++ b/crates/mozart-sat-resolver/src/pool.rs
@@ -299,36 +299,40 @@ impl Pool {
};
}
- // Check provides
+ // Check provides. A package may declare more than one provide link
+ // for the same target (e.g. an `AliasPackage` carries the base's link
+ // and an extra link tagged at the alias's own version), so keep
+ // iterating once a target name matches but the constraint doesn't —
+ // a later link may still satisfy.
for link in &candidate.provides {
- if link.target == name {
- return match constraint {
- None => true,
- Some(vc) => {
- // The provide link has its own constraint; check if they intersect
- if let Ok(provide_vc) = VersionConstraint::parse(&link.constraint) {
- constraints_intersect(vc, &provide_vc)
- } else {
- false
- }
+ if link.target != name {
+ continue;
+ }
+ match constraint {
+ None => return true,
+ Some(vc) => {
+ if let Ok(provide_vc) = VersionConstraint::parse(&link.constraint)
+ && constraints_intersect(vc, &provide_vc)
+ {
+ return true;
}
- };
+ }
}
}
- // Check replaces
for link in &candidate.replaces {
- if link.target == name {
- return match constraint {
- None => true,
- Some(vc) => {
- if let Ok(replace_vc) = VersionConstraint::parse(&link.constraint) {
- constraints_intersect(vc, &replace_vc)
- } else {
- false
- }
+ if link.target != name {
+ continue;
+ }
+ match constraint {
+ None => return true,
+ Some(vc) => {
+ if let Ok(replace_vc) = VersionConstraint::parse(&link.constraint)
+ && constraints_intersect(vc, &replace_vc)
+ {
+ return true;
}
- };
+ }
}
}