mirror of
https://github.com/rust-lang/cargo.git
synced 2025-10-01 11:30:39 +00:00
check that the SAT solver exempts the result from the resolver
This commit is contained in:
parent
f203deaa05
commit
034c5908d8
@ -1,7 +1,10 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use std::cmp::PartialEq;
|
use std::cmp::PartialEq;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::fmt::Write;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use cargo::core::dependency::Kind;
|
use cargo::core::dependency::Kind;
|
||||||
@ -24,17 +27,22 @@ pub fn resolve(deps: Vec<Dependency>, registry: &[Summary]) -> CargoResult<Vec<P
|
|||||||
pub fn resolve_and_validated(
|
pub fn resolve_and_validated(
|
||||||
deps: Vec<Dependency>,
|
deps: Vec<Dependency>,
|
||||||
registry: &[Summary],
|
registry: &[Summary],
|
||||||
sat_resolve: Option<&mut SatResolve>,
|
sat_resolve: Option<SatResolve>,
|
||||||
) -> CargoResult<Vec<PackageId>> {
|
) -> CargoResult<Vec<PackageId>> {
|
||||||
let should_resolve = if let Some(sat) = sat_resolve {
|
let resolve = resolve_with_config_raw(deps.clone(), registry, None);
|
||||||
sat.sat_resolve(&deps)
|
|
||||||
} else {
|
|
||||||
SatResolve::new(registry).sat_resolve(&deps)
|
|
||||||
};
|
|
||||||
let resolve = resolve_with_config_raw(deps, registry, None);
|
|
||||||
assert_eq!(resolve.is_ok(), should_resolve);
|
|
||||||
|
|
||||||
let resolve = resolve?;
|
match resolve {
|
||||||
|
Err(e) => {
|
||||||
|
let sat_resolve = sat_resolve.unwrap_or_else(|| SatResolve::new(registry));
|
||||||
|
if sat_resolve.sat_resolve(&deps) {
|
||||||
|
panic!(
|
||||||
|
"the resolve err but the sat_resolve thinks this will work:\n{}",
|
||||||
|
sat_resolve.use_packages().unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e)
|
||||||
|
}
|
||||||
|
Ok(resolve) => {
|
||||||
let mut stack = vec![pkg_id("root")];
|
let mut stack = vec![pkg_id("root")];
|
||||||
let mut used = HashSet::new();
|
let mut used = HashSet::new();
|
||||||
let mut links = HashSet::new();
|
let mut links = HashSet::new();
|
||||||
@ -83,8 +91,17 @@ pub fn resolve_and_validated(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let sat_resolve = sat_resolve.unwrap_or_else(|| SatResolve::new(registry));
|
||||||
|
if !sat_resolve.sat_is_valid_solution(&out) {
|
||||||
|
panic!(
|
||||||
|
"the sat_resolve err but the resolve thinks this will work:\n{:?}",
|
||||||
|
resolve
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn resolve_with_config(
|
pub fn resolve_with_config(
|
||||||
deps: Vec<Dependency>,
|
deps: Vec<Dependency>,
|
||||||
@ -234,7 +251,9 @@ fn sat_at_most_one_by_key<K: std::hash::Hash + Eq>(
|
|||||||
///
|
///
|
||||||
/// The SAT library dose not optimize for the newer version,
|
/// The SAT library dose not optimize for the newer version,
|
||||||
/// so the selected packages may not match the real resolver.
|
/// so the selected packages may not match the real resolver.
|
||||||
pub struct SatResolve {
|
#[derive(Clone)]
|
||||||
|
pub struct SatResolve(Rc<RefCell<SatResolveInner>>);
|
||||||
|
struct SatResolveInner {
|
||||||
solver: varisat::Solver<'static>,
|
solver: varisat::Solver<'static>,
|
||||||
var_for_is_packages_used: HashMap<PackageId, varisat::Var>,
|
var_for_is_packages_used: HashMap<PackageId, varisat::Var>,
|
||||||
by_name: HashMap<&'static str, Vec<PackageId>>,
|
by_name: HashMap<&'static str, Vec<PackageId>>,
|
||||||
@ -397,27 +416,27 @@ impl SatResolve {
|
|||||||
solver
|
solver
|
||||||
.solve()
|
.solve()
|
||||||
.expect("docs say it can't error in default config");
|
.expect("docs say it can't error in default config");
|
||||||
|
SatResolve(Rc::new(RefCell::new(SatResolveInner {
|
||||||
SatResolve {
|
|
||||||
solver,
|
solver,
|
||||||
var_for_is_packages_used,
|
var_for_is_packages_used,
|
||||||
by_name,
|
by_name,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
}
|
pub fn sat_resolve(&self, deps: &[Dependency]) -> bool {
|
||||||
pub fn sat_resolve(&mut self, deps: &[Dependency]) -> bool {
|
let mut s = self.0.borrow_mut();
|
||||||
let mut assumption = vec![];
|
let mut assumption = vec![];
|
||||||
let mut this_call = None;
|
let mut this_call = None;
|
||||||
|
|
||||||
// the starting `deps` need to be satisfied
|
// the starting `deps` need to be satisfied
|
||||||
for dep in deps.iter() {
|
for dep in deps.iter() {
|
||||||
let empty_vec = vec![];
|
let empty_vec = vec![];
|
||||||
let matches: Vec<varisat::Lit> = self
|
let matches: Vec<varisat::Lit> = s
|
||||||
.by_name
|
.by_name
|
||||||
.get(dep.package_name().as_str())
|
.get(dep.package_name().as_str())
|
||||||
.unwrap_or(&empty_vec)
|
.unwrap_or(&empty_vec)
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&p| dep.matches_id(*p))
|
.filter(|&p| dep.matches_id(*p))
|
||||||
.map(|p| self.var_for_is_packages_used[p].positive())
|
.map(|p| s.var_for_is_packages_used[p].positive())
|
||||||
.collect();
|
.collect();
|
||||||
if matches.is_empty() {
|
if matches.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
@ -425,22 +444,58 @@ impl SatResolve {
|
|||||||
assumption.extend_from_slice(&matches)
|
assumption.extend_from_slice(&matches)
|
||||||
} else {
|
} else {
|
||||||
if this_call.is_none() {
|
if this_call.is_none() {
|
||||||
let new_var = self.solver.new_var();
|
let new_var = s.solver.new_var();
|
||||||
this_call = Some(new_var);
|
this_call = Some(new_var);
|
||||||
assumption.push(new_var.positive());
|
assumption.push(new_var.positive());
|
||||||
}
|
}
|
||||||
let mut matches = matches;
|
let mut matches = matches;
|
||||||
matches.push(this_call.unwrap().negative());
|
matches.push(this_call.unwrap().negative());
|
||||||
self.solver.add_clause(&matches);
|
s.solver.add_clause(&matches);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.solver.assume(&assumption);
|
s.solver.assume(&assumption);
|
||||||
|
|
||||||
self.solver
|
s.solver
|
||||||
.solve()
|
.solve()
|
||||||
.expect("docs say it can't error in default config")
|
.expect("docs say it can't error in default config")
|
||||||
}
|
}
|
||||||
|
pub fn sat_is_valid_solution(&self, pids: &[PackageId]) -> bool {
|
||||||
|
let mut s = self.0.borrow_mut();
|
||||||
|
for p in pids {
|
||||||
|
if p.name().as_str() != "root" && !s.var_for_is_packages_used.contains_key(p) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let assumption: Vec<_> = s
|
||||||
|
.var_for_is_packages_used
|
||||||
|
.iter()
|
||||||
|
.map(|(p, v)| v.lit(pids.contains(p)))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
s.solver.assume(&assumption);
|
||||||
|
|
||||||
|
s.solver
|
||||||
|
.solve()
|
||||||
|
.expect("docs say it can't error in default config")
|
||||||
|
}
|
||||||
|
fn use_packages(&self) -> Option<String> {
|
||||||
|
self.0.borrow().solver.model().map(|lits| {
|
||||||
|
let lits: HashSet<_> = lits
|
||||||
|
.iter()
|
||||||
|
.filter(|l| l.is_positive())
|
||||||
|
.map(|l| l.var())
|
||||||
|
.collect();
|
||||||
|
let mut out = String::new();
|
||||||
|
out.push_str("used:\n");
|
||||||
|
for (p, v) in self.0.borrow().var_for_is_packages_used.iter() {
|
||||||
|
if lits.contains(v) {
|
||||||
|
writeln!(&mut out, " {}", p).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ToDep {
|
pub trait ToDep {
|
||||||
|
@ -39,7 +39,7 @@ proptest! {
|
|||||||
PrettyPrintRegistry(input) in registry_strategy(50, 20, 60)
|
PrettyPrintRegistry(input) in registry_strategy(50, 20, 60)
|
||||||
) {
|
) {
|
||||||
let reg = registry(input.clone());
|
let reg = registry(input.clone());
|
||||||
let mut sat_resolve = SatResolve::new(®);
|
let sat_resolve = SatResolve::new(®);
|
||||||
// there is only a small chance that any one
|
// there is only a small chance that any one
|
||||||
// crate will be interesting.
|
// crate will be interesting.
|
||||||
// So we try some of the most complicated.
|
// So we try some of the most complicated.
|
||||||
@ -47,7 +47,7 @@ proptest! {
|
|||||||
let _ = resolve_and_validated(
|
let _ = resolve_and_validated(
|
||||||
vec![dep_req(&this.name(), &format!("={}", this.version()))],
|
vec![dep_req(&this.name(), &format!("={}", this.version()))],
|
||||||
®,
|
®,
|
||||||
Some(&mut sat_resolve),
|
Some(sat_resolve.clone()),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user