@@ -104,7 +104,7 @@ impl<'a> ToPkgId for (&'a str, String) {
104
104
}
105
105
106
106
macro_rules! pkg {
107
- ( $pkgid: expr => [ $( $deps: expr) ,+] ) => ( {
107
+ ( $pkgid: expr => [ $( $deps: expr) ,+ $ ( , ) * ] ) => ( {
108
108
let d: Vec <Dependency > = vec![ $( $deps. to_dep( ) ) ,+] ;
109
109
let pkgid = $pkgid. to_pkgid( ) ;
110
110
let link = if pkgid. name( ) . ends_with( "-sys" ) { Some ( pkgid. name( ) . as_str( ) ) } else { None } ;
@@ -963,6 +963,174 @@ fn resolving_with_constrained_sibling_transitive_dep_effects() {
963
963
) ;
964
964
}
965
965
966
+ #[ test]
967
+ fn incomplete_information_skiping ( ) {
968
+ // When backtracking due to a failed dependency, if Cargo is
969
+ // trying to be clever and skip irrelevant dependencies, care must
970
+ // be taken to not miss the transitive effects of alternatives.
971
+ // Fuzzing discovered that for some reason cargo was skiping based
972
+ // on incomplete information in the following case:
973
+ // minimized bug found in:
974
+ // https://github.com/rust-lang/cargo/commit/003c29b0c71e5ea28fbe8e72c148c755c9f3f8d9
975
+ let input = vec ! [
976
+ pkg!( ( "a" , "1.0.0" ) ) ,
977
+ pkg!( ( "a" , "1.1.0" ) ) ,
978
+ pkg!( "b" => [ dep( "a" ) ] ) ,
979
+ pkg!( ( "c" , "1.0.0" ) ) ,
980
+ pkg!( ( "c" , "1.1.0" ) ) ,
981
+ pkg!( "d" => [ dep_req( "c" , "=1.0" ) ] ) ,
982
+ pkg!( ( "e" , "1.0.0" ) ) ,
983
+ pkg!( ( "e" , "1.1.0" ) => [ dep_req( "c" , "1.1" ) ] ) ,
984
+ pkg!( "to_yank" ) ,
985
+ pkg!( ( "f" , "1.0.0" ) => [
986
+ dep( "to_yank" ) ,
987
+ dep( "d" ) ,
988
+ ] ) ,
989
+ pkg!( ( "f" , "1.1.0" ) => [ dep( "d" ) ] ) ,
990
+ pkg!( "g" => [
991
+ dep( "b" ) ,
992
+ dep( "e" ) ,
993
+ dep( "f" ) ,
994
+ ] ) ,
995
+ ] ;
996
+ let reg = registry ( input. clone ( ) ) ;
997
+
998
+ let res = resolve ( & pkg_id ( "root" ) , vec ! [ dep( "g" ) ] , & reg) . unwrap ( ) ;
999
+ let package_to_yank = "to_yank" . to_pkgid ( ) ;
1000
+ // this package is not used in the resolution.
1001
+ assert ! ( !res. contains( & package_to_yank) ) ;
1002
+ // so when we yank it
1003
+ let new_reg = registry (
1004
+ input
1005
+ . iter ( )
1006
+ . cloned ( )
1007
+ . filter ( |x| & package_to_yank != x. package_id ( ) )
1008
+ . collect ( ) ,
1009
+ ) ;
1010
+ assert_eq ! ( input. len( ) , new_reg. len( ) + 1 ) ;
1011
+ // it should still build
1012
+ assert ! ( resolve( & pkg_id( "root" ) , vec![ dep( "g" ) ] , & new_reg) . is_ok( ) ) ;
1013
+ }
1014
+
1015
+ #[ test]
1016
+ fn incomplete_information_skiping_2 ( ) {
1017
+ // When backtracking due to a failed dependency, if Cargo is
1018
+ // trying to be clever and skip irrelevant dependencies, care must
1019
+ // be taken to not miss the transitive effects of alternatives.
1020
+ // Fuzzing discovered that for some reason cargo was skiping based
1021
+ // on incomplete information in the following case:
1022
+ // https://github.com/rust-lang/cargo/commit/003c29b0c71e5ea28fbe8e72c148c755c9f3f8d9
1023
+ let input = vec ! [
1024
+ pkg!( ( "b" , "3.8.10" ) ) ,
1025
+ pkg!( ( "b" , "8.7.4" ) ) ,
1026
+ pkg!( ( "b" , "9.4.6" ) ) ,
1027
+ pkg!( ( "c" , "1.8.8" ) ) ,
1028
+ pkg!( ( "c" , "10.2.5" ) ) ,
1029
+ pkg!( ( "d" , "4.1.2" ) => [
1030
+ dep_req( "bad" , "=6.10.9" ) ,
1031
+ ] ) ,
1032
+ pkg!( ( "d" , "5.5.6" ) ) ,
1033
+ pkg!( ( "d" , "5.6.10" ) ) ,
1034
+ pkg!( ( "to_yank" , "8.0.1" ) ) ,
1035
+ pkg!( ( "to_yank" , "8.8.1" ) ) ,
1036
+ pkg!( ( "e" , "4.7.8" ) => [
1037
+ dep_req( "d" , ">=5.5.6, <=5.6.10" ) ,
1038
+ dep_req( "to_yank" , "=8.0.1" ) ,
1039
+ ] ) ,
1040
+ pkg!( ( "e" , "7.4.9" ) => [
1041
+ dep_req( "bad" , "=4.7.5" ) ,
1042
+ ] ) ,
1043
+ pkg!( "f" => [
1044
+ dep_req( "d" , ">=4.1.2, <=5.5.6" ) ,
1045
+ ] ) ,
1046
+ pkg!( "g" => [
1047
+ dep( "bad" ) ,
1048
+ ] ) ,
1049
+ pkg!( ( "h" , "3.8.3" ) => [
1050
+ dep_req( "g" , "*" ) ,
1051
+ ] ) ,
1052
+ pkg!( ( "h" , "6.8.3" ) => [
1053
+ dep( "f" ) ,
1054
+ ] ) ,
1055
+ pkg!( ( "h" , "8.1.9" ) => [
1056
+ dep_req( "to_yank" , "=8.8.1" ) ,
1057
+ ] ) ,
1058
+ pkg!( "i" => [
1059
+ dep_req( "b" , "*" ) ,
1060
+ dep_req( "c" , "*" ) ,
1061
+ dep_req( "e" , "*" ) ,
1062
+ dep_req( "h" , "*" ) ,
1063
+ ] ) ,
1064
+ ] ;
1065
+ let reg = registry ( input. clone ( ) ) ;
1066
+
1067
+ let res = resolve ( & pkg_id ( "root" ) , vec ! [ dep( "i" ) ] , & reg) . unwrap ( ) ;
1068
+ let package_to_yank = ( "to_yank" , "8.8.1" ) . to_pkgid ( ) ;
1069
+ // this package is not used in the resolution.
1070
+ assert ! ( !res. contains( & package_to_yank) ) ;
1071
+ // so when we yank it
1072
+ let new_reg = registry (
1073
+ input
1074
+ . iter ( )
1075
+ . cloned ( )
1076
+ . filter ( |x| & package_to_yank != x. package_id ( ) )
1077
+ . collect ( ) ,
1078
+ ) ;
1079
+ assert_eq ! ( input. len( ) , new_reg. len( ) + 1 ) ;
1080
+ // it should still build
1081
+ assert ! ( resolve( & pkg_id( "root" ) , vec![ dep( "i" ) ] , & new_reg) . is_ok( ) ) ;
1082
+ }
1083
+
1084
+ #[ test]
1085
+ fn incomplete_information_skiping_3 ( ) {
1086
+ // When backtracking due to a failed dependency, if Cargo is
1087
+ // trying to be clever and skip irrelevant dependencies, care must
1088
+ // be taken to not miss the transitive effects of alternatives.
1089
+ // Fuzzing discovered that for some reason cargo was skiping based
1090
+ // on incomplete information in the following case:
1091
+ // minimized bug found in:
1092
+ // https://github.com/rust-lang/cargo/commit/003c29b0c71e5ea28fbe8e72c148c755c9f3f8d9
1093
+ let input = vec ! [
1094
+ pkg!{ ( "to_yank" , "3.0.3" ) } ,
1095
+ pkg!{ ( "to_yank" , "3.3.0" ) } ,
1096
+ pkg!{ ( "to_yank" , "3.3.1" ) } ,
1097
+ pkg!{ ( "a" , "3.3.0" ) => [
1098
+ dep_req( "to_yank" , "=3.0.3" ) ,
1099
+ ] } ,
1100
+ pkg!{ ( "a" , "3.3.2" ) => [
1101
+ dep_req( "to_yank" , "<=3.3.0" ) ,
1102
+ ] } ,
1103
+ pkg!{ ( "b" , "0.1.3" ) => [
1104
+ dep_req( "a" , "=3.3.0" ) ,
1105
+ ] } ,
1106
+ pkg!{ ( "b" , "2.0.2" ) => [
1107
+ dep_req( "to_yank" , "3.3.0" ) ,
1108
+ dep_req( "a" , "*" ) ,
1109
+ ] } ,
1110
+ pkg!{ ( "b" , "2.3.3" ) => [
1111
+ dep_req( "to_yank" , "3.3.0" ) ,
1112
+ dep_req( "a" , "=3.3.0" ) ,
1113
+ ] } ,
1114
+ ] ;
1115
+ let reg = registry ( input. clone ( ) ) ;
1116
+
1117
+ let res = resolve ( & pkg_id ( "root" ) , vec ! [ dep_req( "b" , "*" ) ] , & reg) . unwrap ( ) ;
1118
+ let package_to_yank = ( "to_yank" , "3.0.3" ) . to_pkgid ( ) ;
1119
+ // this package is not used in the resolution.
1120
+ assert ! ( !res. contains( & package_to_yank) ) ;
1121
+ // so when we yank it
1122
+ let new_reg = registry (
1123
+ input
1124
+ . iter ( )
1125
+ . cloned ( )
1126
+ . filter ( |x| & package_to_yank != x. package_id ( ) )
1127
+ . collect ( ) ,
1128
+ ) ;
1129
+ assert_eq ! ( input. len( ) , new_reg. len( ) + 1 ) ;
1130
+ // it should still build
1131
+ assert ! ( resolve( & pkg_id( "root" ) , vec![ dep_req( "b" , "*" ) ] , & new_reg) . is_ok( ) ) ;
1132
+ }
1133
+
966
1134
#[ test]
967
1135
fn resolving_but_no_exists ( ) {
968
1136
let reg = registry ( vec ! [ ] ) ;
0 commit comments