@@ -299,6 +299,15 @@ fn activate_deps_loop(
299299 // not be right, so we can't push into our global cache.
300300 if !just_here_for_the_error_messages && !backtracked {
301301 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+ }
302311 }
303312
304313 match find_candidate (
@@ -842,6 +851,62 @@ impl RemainingCandidates {
842851 }
843852}
844853
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+
845910/// Looks through the states in `backtrack_stack` for dependencies with
846911/// remaining candidates. For each one, also checks if rolling back
847912/// could change the outcome of the failed resolution that caused backtracking
0 commit comments