Skip to content

Commit

Permalink
fix: constraint at root can conflict (#79)
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfv authored Nov 1, 2024
1 parent 59111fb commit f58e000
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 17 deletions.
9 changes: 8 additions & 1 deletion src/conflict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -982,7 +982,14 @@ impl<'i, I: Interner> fmt::Display for DisplayUnsat<'i, I> {

// The only possible conflict at the root level is a Locked conflict
match conflict {
ConflictCause::Constrains(_) | ConflictCause::ForbidMultipleInstances => {
&ConflictCause::Constrains(version_set_id) => {
writeln!(
f,
"{indent}constraint '{version_set}' cannot be fulfilled",
version_set = self.interner.display_version_set(version_set_id),
)?;
}
&ConflictCause::ForbidMultipleInstances => {
unreachable!()
}
&ConflictCause::Locked(solvable_id) => {
Expand Down
26 changes: 18 additions & 8 deletions src/snapshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,19 +355,29 @@ impl<'s> SnapshotProvider<'s> {
}
}

/// Adds another requirement that matches any version of a package
pub fn add_package_requirement(&mut self, name: NameId) -> VersionSetId {
/// Adds another requirement that matches any version of a package.
/// If you use "*" as the matcher, it will match any version of the package.
pub fn add_package_requirement(&mut self, name: NameId, matcher: &str) -> VersionSetId {
let id = self.snapshot.version_sets.max() + self.additional_version_sets.len();

let package = self.package(name);

let version_set = VersionSet {
let matching_candidates = package
.solvables
.iter()
.copied()
.filter(|&s| matcher == "*" || self.solvable(s).display.contains(matcher))
.collect();

self.additional_version_sets.push(VersionSet {
name,
display: "*".to_string(),
matching_candidates: package.solvables.iter().copied().collect(),
};
display: if matcher == "*" {
"*".to_string()
} else {
format!("{} {}", package.name, matcher)
},
matching_candidates,
});

self.additional_version_sets.push(version_set);
VersionSetId::from_usize(id)
}

Expand Down
8 changes: 8 additions & 0 deletions tests/snapshots/solver__root_constraints.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
source: tests/solver.rs
expression: "solve_for_snapshot(snapshot_provider, &[union_req], &[icons_req])"
---
The following packages are incompatible
└─ union * can be installed with any of the following options:
└─ union union=1
├─ constraint 'union 5' cannot be fulfilled
42 changes: 35 additions & 7 deletions tests/solver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1332,9 +1332,9 @@ fn test_snapshot() {

let mut snapshot_provider = snapshot.provider();

let menu_req = snapshot_provider.add_package_requirement(menu_name_id);
let menu_req = snapshot_provider.add_package_requirement(menu_name_id, "*");

assert_snapshot!(solve_for_snapshot(snapshot_provider, &[menu_req]));
assert_snapshot!(solve_for_snapshot(snapshot_provider, &[menu_req], &[]));
}

#[test]
Expand All @@ -1354,12 +1354,34 @@ fn test_snapshot_union_requirements() {

let mut snapshot_provider = snapshot.provider();

let intl_req = snapshot_provider.add_package_requirement(intl_name_id);
let union_req = snapshot_provider.add_package_requirement(union_name_id);
let intl_req = snapshot_provider.add_package_requirement(intl_name_id, "*");
let union_req = snapshot_provider.add_package_requirement(union_name_id, "*");

assert_snapshot!(solve_for_snapshot(
snapshot_provider,
&[intl_req, union_req]
&[intl_req, union_req],
&[]
));
}

#[test]
fn test_root_constraints() {
let provider =
BundleBoxProvider::from_packages(&[("icons", 1, vec![]), ("union", 1, vec!["icons"])]);

let union_name_id = provider.package_name("union");

let snapshot = provider.into_snapshot();

let mut snapshot_provider = snapshot.provider();

let union_req = snapshot_provider.add_package_requirement(union_name_id, "*");
let union_constraint = snapshot_provider.add_package_requirement(union_name_id, "5");

assert_snapshot!(solve_for_snapshot(
snapshot_provider,
&[union_req],
&[union_constraint]
));
}

Expand Down Expand Up @@ -1401,9 +1423,15 @@ fn serialize_snapshot(snapshot: &DependencySnapshot, destination: impl AsRef<std
serde_json::to_writer_pretty(file, snapshot).unwrap()
}

fn solve_for_snapshot(provider: SnapshotProvider, root_reqs: &[VersionSetId]) -> String {
fn solve_for_snapshot(
provider: SnapshotProvider,
root_reqs: &[VersionSetId],
root_constraints: &[VersionSetId],
) -> String {
let mut solver = Solver::new(provider);
let problem = Problem::new().requirements(root_reqs.iter().copied().map(Into::into).collect());
let problem = Problem::new()
.requirements(root_reqs.iter().copied().map(Into::into).collect())
.constraints(root_constraints.iter().copied().map(Into::into).collect());
match solver.solve(problem) {
Ok(solvables) => transaction_to_string(solver.provider(), &solvables),
Err(UnsolvableOrCancelled::Unsolvable(conflict)) => {
Expand Down
2 changes: 1 addition & 1 deletion tools/solve-snapshot/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ fn main() {
0 => {
// Add a package requirement
let (package, _) = snapshot.packages.iter().choose(&mut rng).unwrap();
let package_requirement = provider.add_package_requirement(package);
let package_requirement = provider.add_package_requirement(package, "*");
requirements.push(package_requirement.into());
}
1 => {
Expand Down

0 comments on commit f58e000

Please sign in to comment.