@@ -299,6 +299,15 @@ fn activate_deps_loop(
299
299
// not be right, so we can't push into our global cache.
300
300
if !just_here_for_the_error_messages && !backtracked {
301
301
past_conflicting_activations. insert ( & dep, & conflicting_activations) ;
302
+ if let Some ( c) = generalize_conflicting (
303
+ & cx,
304
+ registry,
305
+ & mut past_conflicting_activations,
306
+ & dep,
307
+ & conflicting_activations,
308
+ ) {
309
+ conflicting_activations = c;
310
+ }
302
311
}
303
312
304
313
match find_candidate (
@@ -842,6 +851,62 @@ impl RemainingCandidates {
842
851
}
843
852
}
844
853
854
+ /// Attempts to find a new conflict that allows a bigger backjump then the input one.
855
+ /// It will add the new conflict to the cache if one is found.
856
+ ///
857
+ /// Panics if the input conflict is not all active in `cx`.
858
+ fn generalize_conflicting (
859
+ cx : & Context ,
860
+ registry : & mut RegistryQueryer < ' _ > ,
861
+ past_conflicting_activations : & mut conflict_cache:: ConflictCache ,
862
+ dep : & Dependency ,
863
+ conflicting_activations : & ConflictMap ,
864
+ ) -> Option < ConflictMap > {
865
+ if conflicting_activations. is_empty ( ) {
866
+ return None ;
867
+ }
868
+ // We need to determine the "age" that this `conflicting_activations` will jump to, and why.
869
+ let ( jumpback_critical_age, jumpback_critical_id) = conflicting_activations
870
+ . keys ( )
871
+ . map ( |& c| ( cx. is_active ( c) . expect ( "not currently active!?" ) , c) )
872
+ . max ( )
873
+ . unwrap ( ) ;
874
+ let jumpback_critical_reason: ConflictReason =
875
+ conflicting_activations[ & jumpback_critical_id] . clone ( ) ;
876
+ // What parents dose that critical activation have
877
+ for ( critical_parent, critical_parents_deps) in
878
+ cx. parents . edges ( & jumpback_critical_id) . filter ( |( p, _) | {
879
+ // it will only help backjump further if it is older then the critical_age
880
+ cx. is_active ( * p) . expect ( "parent not currently active!?" ) < jumpback_critical_age
881
+ } )
882
+ {
883
+ for critical_parents_dep in critical_parents_deps. iter ( ) {
884
+ // A dep is equivalent to one of the things it can resolve to.
885
+ // Thus, if all the things it can resolve to have already ben determined
886
+ // to be conflicting, then we can just say that we conflict with the parent.
887
+ if registry
888
+ . query ( & critical_parents_dep)
889
+ . expect ( "an already used dep now error!?" )
890
+ . iter ( )
891
+ . rev ( ) // the last one to be tried is the least likely to be in the cache, so start with that.
892
+ . all ( |other| {
893
+ let mut con = conflicting_activations. clone ( ) ;
894
+ con. remove ( & jumpback_critical_id) ;
895
+ con. insert ( other. summary . package_id ( ) , jumpback_critical_reason. clone ( ) ) ;
896
+ past_conflicting_activations. contains ( & dep, & con)
897
+ } )
898
+ {
899
+ let mut con = conflicting_activations. clone ( ) ;
900
+ con. remove ( & jumpback_critical_id) ;
901
+ con. insert ( * critical_parent, jumpback_critical_reason) ;
902
+ past_conflicting_activations. insert ( & dep, & con) ;
903
+ return Some ( con) ;
904
+ }
905
+ }
906
+ }
907
+ None
908
+ }
909
+
845
910
/// Looks through the states in `backtrack_stack` for dependencies with
846
911
/// remaining candidates. For each one, also checks if rolling back
847
912
/// could change the outcome of the failed resolution that caused backtracking
0 commit comments