1+ use std:: cell:: RefCell ;
12use std:: cmp:: PartialEq ;
23use std:: cmp:: { max, min} ;
34use std:: collections:: { BTreeMap , BTreeSet , HashMap , HashSet } ;
45use std:: fmt;
6+ use std:: fmt:: Write ;
7+ use std:: rc:: Rc ;
58use std:: time:: Instant ;
69
710use cargo:: core:: dependency:: Kind ;
@@ -17,92 +20,99 @@ use proptest::sample::Index;
1720use proptest:: string:: string_regex;
1821use varisat:: { self , ExtendFormula } ;
1922
20- pub fn resolve (
21- pkg : PackageId ,
22- deps : Vec < Dependency > ,
23- registry : & [ Summary ] ,
24- ) -> CargoResult < Vec < PackageId > > {
25- resolve_with_config ( pkg, deps, registry, None )
23+ pub fn resolve ( deps : Vec < Dependency > , registry : & [ Summary ] ) -> CargoResult < Vec < PackageId > > {
24+ resolve_with_config ( deps, registry, None )
2625}
2726
2827pub fn resolve_and_validated (
29- pkg : PackageId ,
3028 deps : Vec < Dependency > ,
3129 registry : & [ Summary ] ,
32- sat_resolve : Option < & mut SatResolve > ,
30+ sat_resolve : Option < SatResolve > ,
3331) -> CargoResult < Vec < PackageId > > {
34- let should_resolve = if let Some ( sat) = sat_resolve {
35- sat. sat_resolve ( & deps)
36- } else {
37- SatResolve :: new ( registry) . sat_resolve ( & deps)
38- } ;
39- let resolve = resolve_with_config_raw ( pkg, deps, registry, None ) ;
40- assert_eq ! ( resolve. is_ok( ) , should_resolve) ;
41-
42- let resolve = resolve?;
43- let mut stack = vec ! [ pkg] ;
44- let mut used = HashSet :: new ( ) ;
45- let mut links = HashSet :: new ( ) ;
46- while let Some ( p) = stack. pop ( ) {
47- assert ! ( resolve. contains( & p) ) ;
48- if used. insert ( p) {
49- // in the tests all `links` crates end in `-sys`
50- if p. name ( ) . ends_with ( "-sys" ) {
51- assert ! ( links. insert( p. name( ) ) ) ;
32+ let resolve = resolve_with_config_raw ( deps. clone ( ) , registry, None ) ;
33+
34+ match resolve {
35+ Err ( e) => {
36+ let sat_resolve = sat_resolve. unwrap_or_else ( || SatResolve :: new ( registry) ) ;
37+ if sat_resolve. sat_resolve ( & deps) {
38+ panic ! (
39+ "the resolve err but the sat_resolve thinks this will work:\n {}" ,
40+ sat_resolve. use_packages( ) . unwrap( )
41+ ) ;
5242 }
53- stack. extend ( resolve. deps ( p) . map ( |( dp, deps) | {
54- for d in deps {
55- assert ! ( d. matches_id( dp) ) ;
56- }
57- dp
58- } ) ) ;
43+ Err ( e)
5944 }
60- }
61- let out = resolve. sort ( ) ;
62- assert_eq ! ( out. len( ) , used. len( ) ) ;
63-
64- let mut pub_deps: HashMap < PackageId , HashSet < _ > > = HashMap :: new ( ) ;
65- for & p in out. iter ( ) {
66- // make the list of `p` public dependencies
67- let mut self_pub_dep = HashSet :: new ( ) ;
68- self_pub_dep. insert ( p) ;
69- for ( dp, deps) in resolve. deps ( p) {
70- if deps. iter ( ) . any ( |d| d. is_public ( ) ) {
71- self_pub_dep. extend ( pub_deps[ & dp] . iter ( ) . cloned ( ) )
45+ Ok ( resolve) => {
46+ let mut stack = vec ! [ pkg_id( "root" ) ] ;
47+ let mut used = HashSet :: new ( ) ;
48+ let mut links = HashSet :: new ( ) ;
49+ while let Some ( p) = stack. pop ( ) {
50+ assert ! ( resolve. contains( & p) ) ;
51+ if used. insert ( p) {
52+ // in the tests all `links` crates end in `-sys`
53+ if p. name ( ) . ends_with ( "-sys" ) {
54+ assert ! ( links. insert( p. name( ) ) ) ;
55+ }
56+ stack. extend ( resolve. deps ( p) . map ( |( dp, deps) | {
57+ for d in deps {
58+ assert ! ( d. matches_id( dp) ) ;
59+ }
60+ dp
61+ } ) ) ;
62+ }
7263 }
73- }
74- pub_deps. insert ( p, self_pub_dep) ;
64+ let out = resolve. sort ( ) ;
65+ assert_eq ! ( out. len( ) , used. len( ) ) ;
66+
67+ let mut pub_deps: HashMap < PackageId , HashSet < _ > > = HashMap :: new ( ) ;
68+ for & p in out. iter ( ) {
69+ // make the list of `p` public dependencies
70+ let mut self_pub_dep = HashSet :: new ( ) ;
71+ self_pub_dep. insert ( p) ;
72+ for ( dp, deps) in resolve. deps ( p) {
73+ if deps. iter ( ) . any ( |d| d. is_public ( ) ) {
74+ self_pub_dep. extend ( pub_deps[ & dp] . iter ( ) . cloned ( ) )
75+ }
76+ }
77+ pub_deps. insert ( p, self_pub_dep) ;
7578
76- // check if `p` has a public dependencies conflicts
77- let seen_dep: BTreeSet < _ > = resolve
78- . deps ( p)
79- . flat_map ( |( dp, _) | pub_deps[ & dp] . iter ( ) . cloned ( ) )
80- . collect ( ) ;
81- let seen_dep: Vec < _ > = seen_dep. iter ( ) . collect ( ) ;
82- for a in seen_dep. windows ( 2 ) {
83- if a[ 0 ] . name ( ) == a[ 1 ] . name ( ) {
79+ // check if `p` has a public dependencies conflicts
80+ let seen_dep: BTreeSet < _ > = resolve
81+ . deps ( p)
82+ . flat_map ( |( dp, _) | pub_deps[ & dp] . iter ( ) . cloned ( ) )
83+ . collect ( ) ;
84+ let seen_dep: Vec < _ > = seen_dep. iter ( ) . collect ( ) ;
85+ for a in seen_dep. windows ( 2 ) {
86+ if a[ 0 ] . name ( ) == a[ 1 ] . name ( ) {
87+ panic ! (
88+ "the package {:?} can publicly see {:?} and {:?}" ,
89+ p, a[ 0 ] , a[ 1 ]
90+ )
91+ }
92+ }
93+ }
94+ let sat_resolve = sat_resolve. unwrap_or_else ( || SatResolve :: new ( registry) ) ;
95+ if !sat_resolve. sat_is_valid_solution ( & out) {
8496 panic ! (
85- "the package {:?} can publicly see {:?} and {:?}" ,
86- p , a [ 0 ] , a [ 1 ]
87- )
97+ "the sat_resolve err but the resolve thinks this will work: \n {:?}" ,
98+ resolve
99+ ) ;
88100 }
101+ Ok ( out)
89102 }
90103 }
91- Ok ( out)
92104}
93105
94106pub fn resolve_with_config (
95- pkg : PackageId ,
96107 deps : Vec < Dependency > ,
97108 registry : & [ Summary ] ,
98109 config : Option < & Config > ,
99110) -> CargoResult < Vec < PackageId > > {
100- let resolve = resolve_with_config_raw ( pkg , deps, registry, config) ?;
111+ let resolve = resolve_with_config_raw ( deps, registry, config) ?;
101112 Ok ( resolve. sort ( ) )
102113}
103114
104115pub fn resolve_with_config_raw (
105- pkg : PackageId ,
106116 deps : Vec < Dependency > ,
107117 registry : & [ Summary ] ,
108118 config : Option < & Config > ,
@@ -158,7 +168,7 @@ pub fn resolve_with_config_raw(
158168 used : HashSet :: new ( ) ,
159169 } ;
160170 let summary = Summary :: new (
161- pkg ,
171+ pkg_id ( "root" ) ,
162172 deps,
163173 & BTreeMap :: < String , Vec < String > > :: new ( ) ,
164174 None :: < String > ,
@@ -241,7 +251,9 @@ fn sat_at_most_one_by_key<K: std::hash::Hash + Eq>(
241251///
242252/// The SAT library dose not optimize for the newer version,
243253/// so the selected packages may not match the real resolver.
244- pub struct SatResolve {
254+ #[ derive( Clone ) ]
255+ pub struct SatResolve ( Rc < RefCell < SatResolveInner > > ) ;
256+ struct SatResolveInner {
245257 solver : varisat:: Solver < ' static > ,
246258 var_for_is_packages_used : HashMap < PackageId , varisat:: Var > ,
247259 by_name : HashMap < & ' static str , Vec < PackageId > > ,
@@ -404,50 +416,86 @@ impl SatResolve {
404416 solver
405417 . solve ( )
406418 . expect ( "docs say it can't error in default config" ) ;
407-
408- SatResolve {
419+ SatResolve ( Rc :: new ( RefCell :: new ( SatResolveInner {
409420 solver,
410421 var_for_is_packages_used,
411422 by_name,
412- }
423+ } ) ) )
413424 }
414- pub fn sat_resolve ( & mut self , deps : & [ Dependency ] ) -> bool {
425+ pub fn sat_resolve ( & self , deps : & [ Dependency ] ) -> bool {
426+ let mut s = self . 0 . borrow_mut ( ) ;
415427 let mut assumption = vec ! [ ] ;
416428 let mut this_call = None ;
417429
418430 // the starting `deps` need to be satisfied
419431 for dep in deps. iter ( ) {
420432 let empty_vec = vec ! [ ] ;
421- let matches: Vec < varisat:: Lit > = self
433+ let matches: Vec < varisat:: Lit > = s
422434 . by_name
423435 . get ( dep. package_name ( ) . as_str ( ) )
424436 . unwrap_or ( & empty_vec)
425437 . iter ( )
426438 . filter ( |& p| dep. matches_id ( * p) )
427- . map ( |p| self . var_for_is_packages_used [ p] . positive ( ) )
439+ . map ( |p| s . var_for_is_packages_used [ p] . positive ( ) )
428440 . collect ( ) ;
429441 if matches. is_empty ( ) {
430442 return false ;
431443 } else if matches. len ( ) == 1 {
432444 assumption. extend_from_slice ( & matches)
433445 } else {
434446 if this_call. is_none ( ) {
435- let new_var = self . solver . new_var ( ) ;
447+ let new_var = s . solver . new_var ( ) ;
436448 this_call = Some ( new_var) ;
437449 assumption. push ( new_var. positive ( ) ) ;
438450 }
439451 let mut matches = matches;
440452 matches. push ( this_call. unwrap ( ) . negative ( ) ) ;
441- self . solver . add_clause ( & matches) ;
453+ s. solver . add_clause ( & matches) ;
454+ }
455+ }
456+
457+ s. solver . assume ( & assumption) ;
458+
459+ s. solver
460+ . solve ( )
461+ . expect ( "docs say it can't error in default config" )
462+ }
463+ pub fn sat_is_valid_solution ( & self , pids : & [ PackageId ] ) -> bool {
464+ let mut s = self . 0 . borrow_mut ( ) ;
465+ for p in pids {
466+ if p. name ( ) . as_str ( ) != "root" && !s. var_for_is_packages_used . contains_key ( p) {
467+ return false ;
442468 }
443469 }
470+ let assumption: Vec < _ > = s
471+ . var_for_is_packages_used
472+ . iter ( )
473+ . map ( |( p, v) | v. lit ( pids. contains ( p) ) )
474+ . collect ( ) ;
444475
445- self . solver . assume ( & assumption) ;
476+ s . solver . assume ( & assumption) ;
446477
447- self . solver
478+ s . solver
448479 . solve ( )
449480 . expect ( "docs say it can't error in default config" )
450481 }
482+ fn use_packages ( & self ) -> Option < String > {
483+ self . 0 . borrow ( ) . solver . model ( ) . map ( |lits| {
484+ let lits: HashSet < _ > = lits
485+ . iter ( )
486+ . filter ( |l| l. is_positive ( ) )
487+ . map ( |l| l. var ( ) )
488+ . collect ( ) ;
489+ let mut out = String :: new ( ) ;
490+ out. push_str ( "used:\n " ) ;
491+ for ( p, v) in self . 0 . borrow ( ) . var_for_is_packages_used . iter ( ) {
492+ if lits. contains ( v) {
493+ writeln ! ( & mut out, " {}" , p) . unwrap ( ) ;
494+ }
495+ }
496+ out
497+ } )
498+ }
451499}
452500
453501pub trait ToDep {
@@ -856,7 +904,6 @@ fn meta_test_deep_trees_from_strategy() {
856904 let reg = registry ( input. clone ( ) ) ;
857905 for this in input. iter ( ) . rev ( ) . take ( 10 ) {
858906 let res = resolve (
859- pkg_id ( "root" ) ,
860907 vec ! [ dep_req( & this. name( ) , & format!( "={}" , this. version( ) ) ) ] ,
861908 & reg,
862909 ) ;
@@ -898,7 +945,6 @@ fn meta_test_multiple_versions_strategy() {
898945 let reg = registry ( input. clone ( ) ) ;
899946 for this in input. iter ( ) . rev ( ) . take ( 10 ) {
900947 let res = resolve (
901- pkg_id ( "root" ) ,
902948 vec ! [ dep_req( & this. name( ) , & format!( "={}" , this. version( ) ) ) ] ,
903949 & reg,
904950 ) ;
0 commit comments