From 82501a36a0fa6725d656742da42c860e75a89b89 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 2 May 2026 11:57:12 +0900 Subject: feat(resolver): real constraint intersection and replace-aware same-name conflicts `Pool::what_provides` previously accepted any provide/replace candidate because `constraints_intersect` returned true unconditionally; the same-name conflict pass also looked only at canonical names, so a package replacing another at v1.0.0 was treated as a valid provider for a v2.0.0 require and could coexist with the replaced package. Implement interval-based `VersionConstraint::intersects` and index packages by their `replace` targets (matching Composer's `getNames(false)`) when generating same-name conflict rules. Greens 3 installer fixtures: conflict_against_replaced_by_dep_package_problem, provider_conflicts3, replaced_packages_should_not_be_installed. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../mozart-sat-resolver/src/rule_set_generator.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) (limited to 'crates/mozart-sat-resolver/src/rule_set_generator.rs') diff --git a/crates/mozart-sat-resolver/src/rule_set_generator.rs b/crates/mozart-sat-resolver/src/rule_set_generator.rs index bc56dff..83570d5 100644 --- a/crates/mozart-sat-resolver/src/rule_set_generator.rs +++ b/crates/mozart-sat-resolver/src/rule_set_generator.rs @@ -125,14 +125,23 @@ impl<'a> RuleSetGenerator<'a> { self.added_map.insert(current_id); let pkg = self.pool.package_by_id(current_id); - let pkg_name = pkg.name.clone(); + let conflict_names: Vec = + pkg.conflict_names().into_iter().map(String::from).collect(); let requires = pkg.requires.clone(); - // Index by name (for same-name conflict rules later) - self.added_packages_by_name - .entry(pkg_name) - .or_default() - .push(current_id); + // Index by every name this package fully claims (own name + + // `replace` targets). Same-name conflict rules (below) then + // prevent two packages from coexisting under the same logical + // identity. Mirrors `BasePackage::getNames(false)` indexing in + // Composer's RuleSetGenerator::addRulesForPackage — `provide` + // targets are intentionally omitted so that providers can + // coexist with the package they provide. + for name in conflict_names { + self.added_packages_by_name + .entry(name) + .or_default() + .push(current_id); + } // Process each requirement for link in requires { -- cgit v1.3.1