@@ -414,7 +414,7 @@ fn activate(cx: &mut Context,
414
414
parent : Option < & Summary > ,
415
415
candidate : Candidate ,
416
416
method : & Method )
417
- -> CargoResult < Option < ( DepsFrame , Duration ) > > {
417
+ -> ActivateResult < Option < ( DepsFrame , Duration ) > > {
418
418
if let Some ( parent) = parent {
419
419
cx. resolve_graph . push ( GraphNode :: Link ( parent. package_id ( ) . clone ( ) ,
420
420
candidate. summary . package_id ( ) . clone ( ) ) ) ;
@@ -443,7 +443,7 @@ fn activate(cx: &mut Context,
443
443
} ;
444
444
445
445
let now = Instant :: now ( ) ;
446
- let deps = cx. build_deps ( registry, & candidate, method) ?;
446
+ let deps = cx. build_deps ( registry, parent , & candidate, method) ?;
447
447
let frame = DepsFrame {
448
448
parent : candidate,
449
449
remaining_siblings : RcVecIter :: new ( Rc :: new ( deps) ) ,
@@ -536,14 +536,40 @@ impl Ord for DepsFrame {
536
536
enum ConflictReason {
537
537
Semver ,
538
538
Links ( String ) ,
539
+ MissingFeatures ( String ) ,
540
+ }
541
+
542
+ enum ActivateError {
543
+ Error ( :: failure:: Error ) ,
544
+ Conflict ( PackageId , ConflictReason ) ,
545
+ }
546
+ type ActivateResult < T > = Result < T , ActivateError > ;
547
+
548
+ impl From < :: failure:: Error > for ActivateError {
549
+ fn from ( t : :: failure:: Error ) -> Self {
550
+ ActivateError :: Error ( t)
551
+ }
552
+ }
553
+
554
+ impl From < ( PackageId , ConflictReason ) > for ActivateError {
555
+ fn from ( t : ( PackageId , ConflictReason ) ) -> Self {
556
+ ActivateError :: Conflict ( t. 0 , t. 1 )
557
+ }
539
558
}
540
559
541
560
impl ConflictReason {
542
561
fn is_links ( & self ) -> bool {
543
- match * self {
544
- ConflictReason :: Semver => false ,
545
- ConflictReason :: Links ( _) => true ,
562
+ if let ConflictReason :: Links ( _) = * self {
563
+ return true ;
546
564
}
565
+ false
566
+ }
567
+
568
+ fn is_missing_features ( & self ) -> bool {
569
+ if let ConflictReason :: MissingFeatures ( _) = * self {
570
+ return true ;
571
+ }
572
+ false
547
573
}
548
574
}
549
575
@@ -556,6 +582,7 @@ struct BacktrackFrame<'a> {
556
582
parent : Summary ,
557
583
dep : Dependency ,
558
584
features : Rc < Vec < String > > ,
585
+ conflicting_activations : HashMap < PackageId , ConflictReason > ,
559
586
}
560
587
561
588
#[ derive( Clone ) ]
@@ -652,9 +679,12 @@ fn activate_deps_loop<'a>(
652
679
summary : summary. clone ( ) ,
653
680
replace : None ,
654
681
} ;
655
- let res = activate ( & mut cx, registry, None , candidate, method) ?;
656
- if let Some ( ( frame, _) ) = res {
657
- remaining_deps. push ( frame) ;
682
+ let res = activate ( & mut cx, registry, None , candidate, method) ;
683
+ match res {
684
+ Ok ( Some ( ( frame, _) ) ) => remaining_deps. push ( frame) ,
685
+ Ok ( None ) => ( ) ,
686
+ Err ( ActivateError :: Error ( e) ) => return Err ( e) ,
687
+ Err ( ActivateError :: Conflict ( _, _) ) => panic ! ( "bad error from activate" )
658
688
}
659
689
}
660
690
@@ -710,74 +740,96 @@ fn activate_deps_loop<'a>(
710
740
711
741
trace ! ( "{}[{}]>{} {} candidates" , parent. name( ) , cur, dep. name( ) , candidates. len( ) ) ;
712
742
trace ! ( "{}[{}]>{} {} prev activations" , parent. name( ) , cur, dep. name( ) , cx. prev_active( & dep) . len( ) ) ;
713
- let mut remaining_candidates = RemainingCandidates :: new ( & candidates) ;
714
- let next = remaining_candidates. next ( cx. prev_active ( & dep) , & cx. links ) ;
715
743
716
- // Alright, for each candidate that's gotten this far, it meets the
717
- // following requirements:
718
- //
719
- // 1. The version matches the dependency requirement listed for this
720
- // package
721
- // 2. There are no activated versions for this package which are
722
- // semver/links-compatible, or there's an activated version which is
723
- // precisely equal to `candidate`.
724
- //
725
- // This means that we're going to attempt to activate each candidate in
726
- // turn. We could possibly fail to activate each candidate, so we try
727
- // each one in turn.
728
- let ( candidate, has_another) = next. or_else ( |mut conflicting| {
729
- // This dependency has no valid candidate. Backtrack until we
730
- // find a dependency that does have a candidate to try, and try
731
- // to activate that one. This resets the `remaining_deps` to
732
- // their state at the found level of the `backtrack_stack`.
733
- trace ! ( "{}[{}]>{} -- no candidates" , parent. name( ) , cur, dep. name( ) ) ;
734
- find_candidate (
735
- & mut backtrack_stack,
736
- & mut cx,
737
- & mut remaining_deps,
738
- & mut parent,
739
- & mut cur,
740
- & mut dep,
741
- & mut features,
742
- & mut remaining_candidates,
743
- & mut conflicting,
744
- ) . ok_or_else ( || {
745
- activation_error (
746
- & cx,
747
- registry,
748
- & parent,
749
- & dep,
750
- & conflicting,
751
- & candidates,
752
- config,
753
- )
754
- } )
755
- } ) ?;
744
+ let mut remaining_candidates = RemainingCandidates :: new ( & candidates) ;
745
+ let mut successfully_activated = false ;
746
+ let mut conflicting_activations = HashMap :: new ( ) ;
747
+
748
+ while !successfully_activated {
749
+ let next = remaining_candidates. next ( cx. prev_active ( & dep) , & cx. links ) ;
750
+
751
+ // Alright, for each candidate that's gotten this far, it meets the
752
+ // following requirements:
753
+ //
754
+ // 1. The version matches the dependency requirement listed for this
755
+ // package
756
+ // 2. There are no activated versions for this package which are
757
+ // semver/links-compatible, or there's an activated version which is
758
+ // precisely equal to `candidate`.
759
+ //
760
+ // This means that we're going to attempt to activate each candidate in
761
+ // turn. We could possibly fail to activate each candidate, so we try
762
+ // each one in turn.
763
+ let ( candidate, has_another) = next. or_else ( |conflicting| {
764
+ conflicting_activations. extend ( conflicting) ;
765
+ // This dependency has no valid candidate. Backtrack until we
766
+ // find a dependency that does have a candidate to try, and try
767
+ // to activate that one. This resets the `remaining_deps` to
768
+ // their state at the found level of the `backtrack_stack`.
769
+ trace ! ( "{}[{}]>{} -- no candidates" , parent. name( ) , cur, dep. name( ) ) ;
770
+ find_candidate (
771
+ & mut backtrack_stack,
772
+ & mut cx,
773
+ & mut remaining_deps,
774
+ & mut parent,
775
+ & mut cur,
776
+ & mut dep,
777
+ & mut features,
778
+ & mut remaining_candidates,
779
+ & mut conflicting_activations,
780
+ ) . ok_or_else ( || {
781
+ // if we hit an activation error and we are out of other combinations
782
+ // then just report that error
783
+ activation_error (
784
+ & cx,
785
+ registry,
786
+ & parent,
787
+ & dep,
788
+ & conflicting_activations,
789
+ & candidates,
790
+ config,
791
+ )
792
+ } )
793
+ } ) ?;
756
794
757
- // We have a candidate. Add an entry to the `backtrack_stack` so
758
- // we can try the next one if this one fails .
759
- if has_another {
760
- backtrack_stack . push ( BacktrackFrame {
795
+ // We have a candidate. Clone a `BacktrackFrame`
796
+ // so we can add it to the `backtrack_stack` if activation succeeds .
797
+ // We clone now in case `activate` changes `cx` and then fails.
798
+ let backtrack = BacktrackFrame {
761
799
cur,
762
800
context_backup : Context :: clone ( & cx) ,
763
801
deps_backup : <BinaryHeap < DepsFrame > >:: clone ( & remaining_deps) ,
764
- remaining_candidates,
802
+ remaining_candidates : remaining_candidates . clone ( ) ,
765
803
parent : Summary :: clone ( & parent) ,
766
804
dep : Dependency :: clone ( & dep) ,
767
805
features : Rc :: clone ( & features) ,
768
- } ) ;
769
- }
806
+ conflicting_activations : conflicting_activations . clone ( ) ,
807
+ } ;
770
808
771
- let method = Method :: Required {
772
- dev_deps : false ,
773
- features : & features,
774
- uses_default_features : dep. uses_default_features ( ) ,
775
- } ;
776
- trace ! ( "{}[{}]>{} trying {}" , parent. name( ) , cur, dep. name( ) , candidate. summary. version( ) ) ;
777
- let res = activate ( & mut cx, registry, Some ( & parent) , candidate, & method) ?;
778
- if let Some ( ( frame, dur) ) = res {
779
- remaining_deps. push ( frame) ;
780
- deps_time += dur;
809
+ let method = Method :: Required {
810
+ dev_deps : false ,
811
+ features : & features,
812
+ uses_default_features : dep. uses_default_features ( ) ,
813
+ } ;
814
+ trace ! ( "{}[{}]>{} trying {}" , parent. name( ) , cur, dep. name( ) , candidate. summary. version( ) ) ;
815
+ let res = activate ( & mut cx, registry, Some ( & parent) , candidate, & method) ;
816
+ successfully_activated = res. is_ok ( ) ;
817
+
818
+ match res {
819
+ Ok ( Some ( ( frame, dur) ) ) => {
820
+ remaining_deps. push ( frame) ;
821
+ deps_time += dur;
822
+ }
823
+ Ok ( None ) => ( ) ,
824
+ Err ( ActivateError :: Error ( e) ) => return Err ( e) ,
825
+ Err ( ActivateError :: Conflict ( id, reason) ) => { conflicting_activations. insert ( id, reason) ; } ,
826
+ }
827
+
828
+ // Add an entry to the `backtrack_stack` so
829
+ // we can try the next one if this one fails.
830
+ if has_another && successfully_activated {
831
+ backtrack_stack. push ( backtrack) ;
832
+ }
781
833
}
782
834
}
783
835
@@ -824,6 +876,7 @@ fn find_candidate<'a>(
824
876
* dep = frame. dep ;
825
877
* features = frame. features ;
826
878
* remaining_candidates = frame. remaining_candidates ;
879
+ * conflicting_activations = frame. conflicting_activations ;
827
880
return Some ( ( candidate, has_another) ) ;
828
881
}
829
882
}
@@ -865,9 +918,9 @@ fn activation_error(cx: &Context,
865
918
866
919
let mut conflicting_activations: Vec < _ > = conflicting_activations. iter ( ) . collect ( ) ;
867
920
conflicting_activations. sort_unstable ( ) ;
868
- let ( links_errors, other_errors) : ( Vec < _ > , Vec < _ > ) = conflicting_activations. drain ( ..) . rev ( ) . partition ( |& ( _, r) | r. is_links ( ) ) ;
921
+ let ( links_errors, mut other_errors) : ( Vec < _ > , Vec < _ > ) = conflicting_activations. drain ( ..) . rev ( ) . partition ( |& ( _, r) | r. is_links ( ) ) ;
869
922
870
- for & ( p, r) in & links_errors {
923
+ for & ( p, r) in links_errors. iter ( ) {
871
924
if let ConflictReason :: Links ( ref link) = * r {
872
925
msg. push_str ( "\n \n the package `" ) ;
873
926
msg. push_str ( dep. name ( ) ) ;
@@ -880,12 +933,29 @@ fn activation_error(cx: &Context,
880
933
msg. push_str ( & describe_path ( p) ) ;
881
934
}
882
935
883
- if links_errors. is_empty ( ) {
936
+ let ( features_errors, other_errors) : ( Vec < _ > , Vec < _ > ) = other_errors. drain ( ..) . partition ( |& ( _, r) | r. is_missing_features ( ) ) ;
937
+
938
+ for & ( p, r) in features_errors. iter ( ) {
939
+ if let ConflictReason :: MissingFeatures ( ref features) = * r {
940
+ msg. push_str ( "\n \n the package `" ) ;
941
+ msg. push_str ( p. name ( ) ) ;
942
+ msg. push_str ( "` depends on `" ) ;
943
+ msg. push_str ( dep. name ( ) ) ;
944
+ msg. push_str ( "`, with features: `" ) ;
945
+ msg. push_str ( features) ;
946
+ msg. push_str ( "` but `" ) ;
947
+ msg. push_str ( dep. name ( ) ) ;
948
+ msg. push_str ( "` does not have these features.\n " ) ;
949
+ }
950
+ // p == parent so the full path is redundant.
951
+ }
952
+
953
+ if !other_errors. is_empty ( ) {
884
954
msg. push_str ( "\n \n all possible versions conflict with \
885
955
previously selected packages.") ;
886
956
}
887
957
888
- for & ( p, _) in & other_errors {
958
+ for & ( p, _) in other_errors. iter ( ) {
889
959
msg. push_str ( "\n \n previously selected " ) ;
890
960
msg. push_str ( & describe_path ( p) ) ;
891
961
}
@@ -1070,9 +1140,9 @@ impl<'r> Requirements<'r> {
1070
1140
}
1071
1141
}
1072
1142
1073
- // Takes requested features for a single package from the input Method and
1074
- // recurses to find all requested features, dependencies and requested
1075
- // dependency features in a Requirements object, returning it to the resolver.
1143
+ /// Takes requested features for a single package from the input Method and
1144
+ /// recurses to find all requested features, dependencies and requested
1145
+ /// dependency features in a Requirements object, returning it to the resolver.
1076
1146
fn build_requirements < ' a , ' b : ' a > ( s : & ' a Summary , method : & ' b Method )
1077
1147
-> CargoResult < Requirements < ' a > > {
1078
1148
let mut reqs = Requirements :: new ( s) ;
@@ -1147,12 +1217,13 @@ impl<'a> Context<'a> {
1147
1217
1148
1218
fn build_deps ( & mut self ,
1149
1219
registry : & mut Registry ,
1220
+ parent : Option < & Summary > ,
1150
1221
candidate : & Summary ,
1151
- method : & Method ) -> CargoResult < Vec < DepInfo > > {
1222
+ method : & Method ) -> ActivateResult < Vec < DepInfo > > {
1152
1223
// First, figure out our set of dependencies based on the requested set
1153
1224
// of features. This also calculates what features we're going to enable
1154
1225
// for our own dependencies.
1155
- let deps = self . resolve_features ( candidate, method) ?;
1226
+ let deps = self . resolve_features ( parent , candidate, method) ?;
1156
1227
1157
1228
// Next, transform all dependencies into a list of possible candidates
1158
1229
// which can satisfy that dependency.
@@ -1263,9 +1334,10 @@ impl<'a> Context<'a> {
1263
1334
1264
1335
/// Return all dependencies and the features we want from them.
1265
1336
fn resolve_features < ' b > ( & mut self ,
1337
+ parent : Option < & Summary > ,
1266
1338
s : & ' b Summary ,
1267
1339
method : & ' b Method )
1268
- -> CargoResult < Vec < ( Dependency , Vec < String > ) > > {
1340
+ -> ActivateResult < Vec < ( Dependency , Vec < String > ) > > {
1269
1341
let dev_deps = match * method {
1270
1342
Method :: Everything => true ,
1271
1343
Method :: Required { dev_deps, .. } => dev_deps,
@@ -1300,7 +1372,7 @@ impl<'a> Context<'a> {
1300
1372
base. extend ( dep. features ( ) . iter ( ) . cloned ( ) ) ;
1301
1373
for feature in base. iter ( ) {
1302
1374
if feature. contains ( '/' ) {
1303
- bail ! ( "feature names may not contain slashes: `{}`" , feature) ;
1375
+ return Err ( format_err ! ( "feature names may not contain slashes: `{}`" , feature) . into ( ) ) ;
1304
1376
}
1305
1377
}
1306
1378
ret. push ( ( dep. clone ( ) , base) ) ;
@@ -1314,8 +1386,11 @@ impl<'a> Context<'a> {
1314
1386
. map ( |s| & s[ ..] )
1315
1387
. collect :: < Vec < & str > > ( ) ;
1316
1388
let features = unknown. join ( ", " ) ;
1317
- bail ! ( "Package `{}` does not have these features: `{}`" ,
1318
- s. package_id( ) , features)
1389
+ return Err ( match parent {
1390
+ None => format_err ! ( "Package `{}` does not have these features: `{}`" ,
1391
+ s. package_id( ) , features) . into ( ) ,
1392
+ Some ( p) => ( p. package_id ( ) . clone ( ) , ConflictReason :: MissingFeatures ( features) ) . into ( ) ,
1393
+ } ) ;
1319
1394
}
1320
1395
1321
1396
// Record what list of features is active for this package.
0 commit comments