@@ -909,67 +909,137 @@ fn generalize_conflicting(
909
909
return None ;
910
910
}
911
911
912
+ let our_candidates: HashSet < PackageId > =
913
+ our_candidates. iter ( ) . map ( |our| our. package_id ( ) ) . collect ( ) ;
914
+
912
915
// What parents does that critical activation have
913
916
for ( critical_parent, critical_parents_deps) in
914
917
cx. parents . edges ( & backtrack_critical_id) . filter ( |( p, _) | {
915
918
// it will only help backjump further if it is older then the critical_age
916
919
cx. is_active ( * p) . expect ( "parent not currently active!?" ) < backtrack_critical_age
917
920
} )
918
921
{
919
- for critical_parents_dep in critical_parents_deps. iter ( ) {
920
- let critical_parent_candidates = registry
922
+ ' dep: for critical_parents_dep in critical_parents_deps. iter ( ) {
923
+ let mut con = conflicting_activations. clone ( ) ;
924
+ con. remove ( & backtrack_critical_id) ;
925
+ con. insert ( * critical_parent, backtrack_critical_reason. clone ( ) ) ;
926
+
927
+ for other in registry
921
928
. query ( critical_parents_dep)
922
- . expect ( "an already used dep now error!?" ) ;
929
+ . expect ( "an already used dep now error!?" )
930
+ . iter ( )
931
+ {
932
+ if ( our_activation_key
933
+ . map_or ( false , |our| other. package_id ( ) . as_activations_key ( ) == our)
934
+ || our_link. map_or ( false , |_| other. links ( ) == our_link) )
935
+ && !our_candidates. contains ( & other. package_id ( ) )
936
+ {
937
+ continue ;
938
+ }
923
939
924
- if (
925
- our_activation_key. is_some ( )
926
- && critical_parent_candidates. iter ( ) . all ( |other| {
927
- other. package_id ( ) . as_activations_key ( ) == our_activation_key. unwrap ( )
928
- && our_candidates
929
- . iter ( )
930
- . all ( |our| our. package_id ( ) != other. package_id ( ) )
931
- } )
932
- // all of `critical_parent_candidates` are semver compatible with all of `our_candidates`
933
- // and we have none in common. Thus `dep` can not be resolved when `critical_parents_dep` has bean resolved.
934
- ) || (
935
- our_link. is_some ( )
936
- && critical_parent_candidates. iter ( ) . all ( |other| {
937
- other. links ( ) == our_link
938
- && our_candidates
939
- . iter ( )
940
- . all ( |our| our. package_id ( ) != other. package_id ( ) )
941
- } )
942
- // all of `critical_parent_candidates` have the same `links` as all of `our_candidates`
943
- // and we have none in common. Thus `dep` can not be resolved when `critical_parents_dep` has bean resolved.
944
- ) {
945
- // but that is not how the cache is set up. So we add the less general but much faster,
946
- // "our dep will not succeed if critical_parent is activated".
947
- let mut con = conflicting_activations. clone ( ) ;
948
- con. remove ( & backtrack_critical_id) ;
949
- con. insert ( * critical_parent, backtrack_critical_reason) ;
950
-
951
- if cfg ! ( debug_assertions) {
952
- // the entire point is to find an older conflict, so let's make sure we did
953
- let new_age = con
954
- . keys ( )
955
- . map ( |& c| cx. is_active ( c) . expect ( "not currently active!?" ) )
956
- . max ( )
957
- . unwrap ( ) ;
958
- assert ! (
959
- new_age < backtrack_critical_age,
960
- "new_age {} < backtrack_critical_age {}" ,
961
- new_age,
962
- backtrack_critical_age
963
- ) ;
940
+ // ok so we dont have a semver nor a links problem with `critical_parents_dep`
941
+ // getting set to `other`, maybe it still wont work do to one of its dependencies.
942
+ if let Some ( conflicting) = generalize_children_conflicting (
943
+ cx,
944
+ backtrack_critical_age,
945
+ registry,
946
+ past_conflicting_activations,
947
+ dep,
948
+ & other,
949
+ * critical_parent,
950
+ ) {
951
+ con. extend ( conflicting. into_iter ( ) ) ;
952
+ continue ;
953
+ } else {
954
+ continue ' dep;
964
955
}
965
- past_conflicting_activations. insert ( dep, & con) ;
966
- return Some ( con) ;
967
956
}
957
+
958
+ if cfg ! ( debug_assertions) {
959
+ // the entire point is to find an older conflict, so let's make sure we did
960
+ let new_age = con
961
+ . keys ( )
962
+ . map ( |& c| cx. is_active ( c) . expect ( "not currently active!?" ) )
963
+ . max ( )
964
+ . unwrap ( ) ;
965
+ assert ! (
966
+ new_age < backtrack_critical_age,
967
+ "new_age {} < backtrack_critical_age {}" ,
968
+ new_age,
969
+ backtrack_critical_age
970
+ ) ;
971
+ }
972
+ past_conflicting_activations. insert ( dep, & con) ;
973
+ return Some ( con) ;
968
974
}
969
975
}
970
976
None
971
977
}
972
978
979
+ /// Sees if the candidate is not usable because one of its children will have a conflict
980
+ ///
981
+ /// Panics if the input conflict is not all active in `cx`.
982
+ fn generalize_children_conflicting (
983
+ cx : & Context ,
984
+ critical_age : usize ,
985
+ registry : & mut RegistryQueryer < ' _ > ,
986
+ past_conflicting_activations : & mut conflict_cache:: ConflictCache ,
987
+ dep : & Dependency ,
988
+ candidate : & Summary ,
989
+ parent : PackageId ,
990
+ ) -> Option < ConflictMap > {
991
+ let method = Method :: Required {
992
+ dev_deps : false ,
993
+ features : Rc :: new ( dep. features ( ) . iter ( ) . cloned ( ) . collect ( ) ) ,
994
+ all_features : false ,
995
+ uses_default_features : dep. uses_default_features ( ) ,
996
+ } ;
997
+ let mut out = ConflictMap :: new ( ) ;
998
+ match registry. build_deps ( Some ( parent) , candidate, & method) {
999
+ Err ( ActivateError :: Fatal ( _) ) => return None ,
1000
+ Err ( ActivateError :: Conflict ( pid, reason) ) => {
1001
+ out. insert ( pid, reason) ;
1002
+ }
1003
+ Ok ( deps) => {
1004
+ let con = deps
1005
+ . 1
1006
+ . iter ( )
1007
+ . filter_map ( |( ref new_dep, _, _) | {
1008
+ past_conflicting_activations. find (
1009
+ new_dep,
1010
+ & |id| {
1011
+ if id == candidate. package_id ( ) {
1012
+ // we are imagining that we used other instead
1013
+ Some ( critical_age)
1014
+ } else {
1015
+ cx. is_active ( id) . filter ( |& age|
1016
+ // we only care about things that are older then critical_age
1017
+ age < critical_age)
1018
+ }
1019
+ } ,
1020
+ None ,
1021
+ )
1022
+ } )
1023
+ . next ( ) ?;
1024
+ out. extend (
1025
+ con. iter ( )
1026
+ . filter ( |( pid, _) | * * pid != candidate. package_id ( ) )
1027
+ . map ( |( & pid, reason) | ( pid, reason. clone ( ) ) ) ,
1028
+ ) ;
1029
+ }
1030
+ } ;
1031
+ // If one of candidate deps is known unresolvable
1032
+ // then candidate will not succeed.
1033
+ // How ever if candidate is part of the reason that
1034
+ // one of its deps conflicts then
1035
+ // we can make a stronger statement
1036
+ // because candidate will definitely be activated when
1037
+ // we try its dep.
1038
+ out. remove ( & candidate. package_id ( ) ) ;
1039
+
1040
+ Some ( out)
1041
+ }
1042
+
973
1043
/// Looks through the states in `backtrack_stack` for dependencies with
974
1044
/// remaining candidates. For each one, also checks if rolling back
975
1045
/// could change the outcome of the failed resolution that caused backtracking
0 commit comments