aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-05-04 00:16:43 +0900
committernsfisis <nsfisis@gmail.com>2026-05-04 00:16:43 +0900
commit5fc05048a456ce18fd9408ea985031865cf45550 (patch)
tree9d01068a076f096874c188f0622f260920d94476 /crates
parent16f8cf26db22c4fb1073b55d57d31110ea9773cc (diff)
downloadphp-mozart-5fc05048a456ce18fd9408ea985031865cf45550.tar.gz
php-mozart-5fc05048a456ce18fd9408ea985031865cf45550.tar.zst
php-mozart-5fc05048a456ce18fd9408ea985031865cf45550.zip
fix(resolver): rewrite self.version on materialized root aliases
Mirror Composer's `AliasPackage::replaceSelfVersionDependencies`: a base package's `replace` / `provide` / `conflict` link whose constraint matches the base's own version (the resolved form of `self.version`) is duplicated on the alias at the alias's version. A root require like `a/aliased: dev-next as 4.1.0-RC2` paired with `replace: { foo: self.version }` previously left the alias with a `dev-next` constraint, so a transitive `foo ^4.0` requirement saw no numeric provider and the solver bailed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates')
-rw-r--r--crates/mozart-registry/src/resolver.rs35
-rw-r--r--crates/mozart/tests/installer.rs2
2 files changed, 33 insertions, 4 deletions
diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs
index a59d330..c592e01 100644
--- a/crates/mozart-registry/src/resolver.rs
+++ b/crates/mozart-registry/src/resolver.rs
@@ -1429,14 +1429,43 @@ pub async fn resolve(request: &ResolveRequest) -> Result<Vec<ResolvedPackage>, R
.is_alias_of
.clone()
.unwrap_or_else(|| input.version.clone());
+ // Extend `self.version`-derived `replace` / `provide` /
+ // `conflict` links with an extra entry pinned at the
+ // alias's own version. Mirrors Composer's
+ // `AliasPackage::replaceSelfVersionDependencies`: a base
+ // link whose constraint matches the base's own version
+ // (the resolved form of `self.version`) is duplicated
+ // under the alias at the alias's version, so a transitive
+ // require like `a/aliased-replaced ^4.0` can match the
+ // alias even when the base is at a non-matching dev
+ // version. Without this, the alias's replace map keeps
+ // the base's `dev-next` constraint and the requirement
+ // never sees a numeric provider.
+ let alias_extra_self_links = |links: &[PoolLink]| -> Vec<PoolLink> {
+ links
+ .iter()
+ .filter(|l| l.constraint == input.version)
+ .map(|l| PoolLink {
+ target: l.target.clone(),
+ constraint: alias.alias_normalized.clone(),
+ source: l.source.clone(),
+ })
+ .collect()
+ };
+ let mut alias_replaces = input.replaces.clone();
+ alias_replaces.extend(alias_extra_self_links(&input.replaces));
+ let mut alias_provides = input.provides.clone();
+ alias_provides.extend(alias_extra_self_links(&input.provides));
+ let mut alias_conflicts = input.conflicts.clone();
+ alias_conflicts.extend(alias_extra_self_links(&input.conflicts));
new_aliases.push(PoolPackageInput {
name: input.name.clone(),
version: alias.alias_normalized.clone(),
pretty_version: alias.alias.clone(),
requires: input.requires.clone(),
- replaces: input.replaces.clone(),
- provides: input.provides.clone(),
- conflicts: input.conflicts.clone(),
+ replaces: alias_replaces,
+ provides: alias_provides,
+ conflicts: alias_conflicts,
is_fixed: false,
is_alias_of: Some(target_normalized),
});
diff --git a/crates/mozart/tests/installer.rs b/crates/mozart/tests/installer.rs
index b998793..968cdb1 100644
--- a/crates/mozart/tests/installer.rs
+++ b/crates/mozart/tests/installer.rs
@@ -253,7 +253,7 @@ installer_fixture!(alias_solver_problems2);
installer_fixture!(alias_with_reference);
installer_fixture!(aliased_priority);
installer_fixture!(aliased_priority_conflicting);
-installer_fixture!(aliases_with_require_dev, ignore);
+installer_fixture!(aliases_with_require_dev);
installer_fixture!(broken_deps_do_not_replace);
installer_fixture!(circular_dependency);
installer_fixture!(circular_dependency2);