Skip to content

Commit 61c8aee

Browse files
committed
count rejected decision and steps in conflict resolution
1 parent 52d7677 commit 61c8aee

File tree

3 files changed

+68
-52
lines changed

3 files changed

+68
-52
lines changed

src/internal/core.rs

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ impl<DP: DependencyProvider> State<DP> {
172172
self.build_derivation_tree(terminal_incompat_id)
173173
})?;
174174
for (p, _) in self.incompatibility_store[root_cause].iter() {
175-
*self.conflict_count.entry(*p).or_default() += 1;
175+
*self.conflict_count.entry(p).or_default() += 1;
176176
}
177177
self.unit_propagation_buffer.clear();
178178
self.unit_propagation_buffer.push(package_almost);
@@ -207,34 +207,38 @@ impl<DP: DependencyProvider> State<DP> {
207207
.is_terminal(self.root_package, &self.root_version)
208208
{
209209
return Err(current_incompat_id);
210-
} else {
211-
let (package, satisfier_search_result) = self.partial_solution.satisfier_search(
212-
&self.incompatibility_store[current_incompat_id],
213-
&self.incompatibility_store,
214-
);
215-
match satisfier_search_result {
216-
SatisfierSearch::DifferentDecisionLevels {
210+
}
211+
let (package, satisfier_search_result) = self.partial_solution.satisfier_search(
212+
&self.incompatibility_store[current_incompat_id],
213+
&self.incompatibility_store,
214+
);
215+
match satisfier_search_result {
216+
SatisfierSearch::DifferentDecisionLevels {
217+
previous_satisfier_level,
218+
} => {
219+
self.backtrack(
220+
current_incompat_id,
221+
current_incompat_changed,
217222
previous_satisfier_level,
218-
} => {
219-
self.backtrack(
220-
current_incompat_id,
221-
current_incompat_changed,
222-
previous_satisfier_level,
223-
);
224-
log::info!("backtrack to {:?}", previous_satisfier_level);
225-
return Ok((package, current_incompat_id));
226-
}
227-
SatisfierSearch::SameDecisionLevels { satisfier_cause } => {
228-
let prior_cause = Incompatibility::prior_cause(
229-
current_incompat_id,
230-
satisfier_cause,
231-
package,
232-
&self.incompatibility_store,
233-
);
234-
log::info!("prior cause: {}", prior_cause.display(&self.package_store));
235-
current_incompat_id = self.incompatibility_store.alloc(prior_cause);
236-
current_incompat_changed = true;
223+
);
224+
log::info!("backtrack to {:?}", previous_satisfier_level);
225+
return Ok((package, current_incompat_id));
226+
}
227+
SatisfierSearch::SameDecisionLevels { satisfier_cause } => {
228+
let prior_cause = Incompatibility::prior_cause(
229+
current_incompat_id,
230+
satisfier_cause,
231+
package,
232+
&self.incompatibility_store,
233+
);
234+
235+
for (p, _) in prior_cause.iter() {
236+
*self.conflict_count.entry(p).or_default() += 1;
237237
}
238+
239+
log::info!("prior cause: {}", prior_cause.display(&self.package_store));
240+
current_incompat_id = self.incompatibility_store.alloc(prior_cause);
241+
current_incompat_changed = true;
238242
}
239243
}
240244
}

src/internal/partial_solution.rs

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -362,34 +362,39 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
362362
version: DP::V,
363363
new_incompatibilities: std::ops::Range<IncompId<DP::P, DP::VS, DP::M>>,
364364
store: &Arena<Incompatibility<DP::P, DP::VS, DP::M>>,
365-
) {
365+
) -> Option<IncompId<DP::P, DP::VS, DP::M>> {
366366
if !self.has_ever_backtracked {
367-
// Nothing has yet gone wrong during this resolution. This call is unlikely to be the first problem.
367+
// Fast path: Nothing has yet gone wrong during this resolution. This call is unlikely to be the first problem.
368368
// So let's live with a little bit of risk and add the decision without checking the dependencies.
369369
// The worst that can happen is we will have to do a full backtrack which only removes this one decision.
370370
log::info!("add_decision: {package:?} @ {version} without checking dependencies");
371371
self.add_decision(package, version);
372+
return None;
373+
}
374+
375+
// Check if any of the dependencies preclude deciding on this crate version.
376+
let package_term = Term::exact(version.clone());
377+
let relation = |incompat: IncompId<DP::P, DP::VS, DP::M>| {
378+
store[incompat].relation(|p| {
379+
// The current package isn't part of the package assignments yet.
380+
if p == package {
381+
Some(&package_term)
382+
} else {
383+
self.term_intersection_for_package(p)
384+
}
385+
})
386+
};
387+
if let Some(satisfied) = Id::range_to_iter(new_incompatibilities)
388+
.find(|incompat| relation(*incompat) == Relation::Satisfied)
389+
{
390+
log::info!(
391+
"rejecting decision {package:?} @ {version} because its dependencies conflict"
392+
);
393+
Some(satisfied)
372394
} else {
373-
// Check if any of the new dependencies preclude deciding on this crate version.
374-
let exact = Term::exact(version.clone());
375-
let not_satisfied = |incompat: &Incompatibility<DP::P, DP::VS, DP::M>| {
376-
incompat.relation(|p| {
377-
if p == package {
378-
Some(&exact)
379-
} else {
380-
self.term_intersection_for_package(p)
381-
}
382-
}) != Relation::Satisfied
383-
};
384-
385-
// Check none of the dependencies (new_incompatibilities)
386-
// would create a conflict (be satisfied).
387-
if store[new_incompatibilities].iter().all(not_satisfied) {
388-
log::info!("add_decision: {package:?} @ {version}");
389-
self.add_decision(package, version);
390-
} else {
391-
log::info!("not adding {package:?} @ {version} because of its dependencies",);
392-
}
395+
log::info!("adding decision: {package:?} @ {version}");
396+
self.add_decision(package, version);
397+
None
393398
}
394399
}
395400

src/solver.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,16 @@ pub fn resolve<DP: DependencyProvider>(
175175
let dep_incompats =
176176
state.add_incompatibility_from_dependencies(p, v.clone(), dependencies);
177177

178-
state
179-
.partial_solution
180-
.add_version(p, v, dep_incompats, &state.incompatibility_store);
178+
if let Some(conflict) = state.partial_solution.add_version(
179+
p,
180+
v,
181+
dep_incompats,
182+
&state.incompatibility_store,
183+
) {
184+
for (incompat_package, _) in state.incompatibility_store[conflict].iter() {
185+
*state.conflict_count.entry(incompat_package).or_default() += 1;
186+
}
187+
}
181188
} else {
182189
// `dep_incompats` are already in `incompatibilities` so we know there are not satisfied
183190
// terms and can add the decision directly.

0 commit comments

Comments
 (0)