Skip to content

Commit 6cfd4e2

Browse files
committed
Auto merge of #5044 - Eh2406:PeekAtRemainingCandidates, r=alexcrichton
make RemainingCandidates::next peekable. `candidates.next` always came with a `candidates.clone().next(prev_active).is_ok` so let's just make that part of `next`. no `clone` needed.
2 parents fe0c18b + 0be926d commit 6cfd4e2

File tree

1 file changed

+94
-96
lines changed

1 file changed

+94
-96
lines changed

src/cargo/core/resolver/mod.rs

+94-96
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ impl ConflictReason {
547547
}
548548
}
549549

550+
#[derive(Clone)]
550551
struct BacktrackFrame<'a> {
551552
cur: usize,
552553
context_backup: Context<'a>,
@@ -562,10 +563,20 @@ struct RemainingCandidates {
562563
remaining: RcVecIter<Candidate>,
563564
// note: change to RcList or something if clone is to expensive
564565
conflicting_prev_active: HashMap<PackageId, ConflictReason>,
566+
// This is a inlined peekable generator
567+
has_another: Option<Candidate>,
565568
}
566569

567570
impl RemainingCandidates {
568-
fn next(&mut self, prev_active: &[Summary], links: &HashMap<String, PackageId>) -> Result<Candidate, HashMap<PackageId, ConflictReason>> {
571+
fn new(candidates: &Rc<Vec<Candidate>>) -> RemainingCandidates {
572+
RemainingCandidates {
573+
remaining: RcVecIter::new(Rc::clone(candidates)),
574+
conflicting_prev_active: HashMap::new(),
575+
has_another: None,
576+
}
577+
}
578+
579+
fn next(&mut self, prev_active: &[Summary], links: &HashMap<String, PackageId>) -> Result<(Candidate, bool), HashMap<PackageId, ConflictReason>> {
569580
// Filter the set of candidates based on the previously activated
570581
// versions for this dependency. We can actually use a version if it
571582
// precisely matches an activated version or if it is otherwise
@@ -578,6 +589,7 @@ impl RemainingCandidates {
578589
// When we are done we return the set of previously activated
579590
// that conflicted with the ones we tried. If any of these change
580591
// then we would have considered different candidates.
592+
use std::mem::replace;
581593
for (_, b) in self.remaining.by_ref() {
582594
if let Some(link) = b.summary.links() {
583595
if let Some(a) = links.get(link) {
@@ -587,15 +599,22 @@ impl RemainingCandidates {
587599
}
588600
}
589601
}
590-
if let Some(a) = prev_active.iter().find(|a| compatible(a.version(), b.summary.version())) {
602+
if let Some(a) = prev_active
603+
.iter()
604+
.find(|a| compatible(a.version(), b.summary.version()))
605+
{
591606
if *a != b.summary {
592607
self.conflicting_prev_active.insert(a.package_id().clone(), ConflictReason::Semver);
593-
continue
608+
continue;
594609
}
595610
}
596-
return Ok(b);
611+
if let Some(r) = replace(&mut self.has_another, Some(b)) {
612+
return Ok((r, true));
613+
}
597614
}
598-
Err(self.conflicting_prev_active.clone())
615+
replace(&mut self.has_another, None)
616+
.map(|r| (r, false))
617+
.ok_or_else(|| self.conflicting_prev_active.clone())
599618
}
600619
}
601620

@@ -604,11 +623,12 @@ impl RemainingCandidates {
604623
///
605624
/// If all dependencies can be activated and resolved to a version in the
606625
/// dependency graph, cx.resolve is returned.
607-
fn activate_deps_loop<'a>(mut cx: Context<'a>,
608-
registry: &mut Registry,
609-
summaries: &[(Summary, Method)],
610-
config: Option<&Config>)
611-
-> CargoResult<Context<'a>> {
626+
fn activate_deps_loop<'a>(
627+
mut cx: Context<'a>,
628+
registry: &mut Registry,
629+
summaries: &[(Summary, Method)],
630+
config: Option<&Config>,
631+
) -> CargoResult<Context<'a>> {
612632
// Note that a `BinaryHeap` is used for the remaining dependencies that need
613633
// activation. This heap is sorted such that the "largest value" is the most
614634
// constrained dependency, or the one with the least candidates.
@@ -620,7 +640,10 @@ fn activate_deps_loop<'a>(mut cx: Context<'a>,
620640
let mut remaining_deps = BinaryHeap::new();
621641
for &(ref summary, ref method) in summaries {
622642
debug!("initial activation: {}", summary.package_id());
623-
let candidate = Candidate { summary: summary.clone(), replace: None };
643+
let candidate = Candidate {
644+
summary: summary.clone(),
645+
replace: None,
646+
};
624647
let res = activate(&mut cx, registry, None, candidate, method)?;
625648
if let Some((frame, _)) = res {
626649
remaining_deps.push(frame);
@@ -647,7 +670,6 @@ fn activate_deps_loop<'a>(mut cx: Context<'a>,
647670
// backtracking states where if we hit an error we can return to in order to
648671
// attempt to continue resolving.
649672
while let Some(mut deps_frame) = remaining_deps.pop() {
650-
651673
// If we spend a lot of time here (we shouldn't in most cases) then give
652674
// a bit of a visual indicator as to what we're doing. Only enable this
653675
// when stderr is a tty (a human is likely to be watching) to ensure we
@@ -659,10 +681,8 @@ fn activate_deps_loop<'a>(mut cx: Context<'a>,
659681
// to amortize the cost of the current time lookup.
660682
ticks += 1;
661683
if let Some(config) = config {
662-
if config.shell().is_err_tty() &&
663-
!printed &&
664-
ticks % 1000 == 0 &&
665-
start.elapsed() - deps_time > time_to_print
684+
if config.shell().is_err_tty() && !printed && ticks % 1000 == 0
685+
&& start.elapsed() - deps_time > time_to_print
666686
{
667687
printed = true;
668688
config.shell().status("Resolving", "dependency graph...")?;
@@ -680,20 +700,10 @@ fn activate_deps_loop<'a>(mut cx: Context<'a>,
680700
let (mut parent, (mut cur, (mut dep, candidates, mut features))) = frame;
681701
assert!(!remaining_deps.is_empty());
682702

683-
let (next, has_another, remaining_candidates) = {
684-
let prev_active = cx.prev_active(&dep);
685-
trace!("{}[{}]>{} {} candidates", parent.name(), cur, dep.name(),
686-
candidates.len());
687-
trace!("{}[{}]>{} {} prev activations", parent.name(), cur,
688-
dep.name(), prev_active.len());
689-
let mut candidates = RemainingCandidates {
690-
remaining: RcVecIter::new(Rc::clone(&candidates)),
691-
conflicting_prev_active: HashMap::new(),
692-
};
693-
(candidates.next(prev_active, &cx.links),
694-
candidates.clone().next(prev_active, &cx.links).is_ok(),
695-
candidates)
696-
};
703+
trace!("{}[{}]>{} {} candidates", parent.name(), cur, dep.name(), candidates.len());
704+
trace!("{}[{}]>{} {} prev activations", parent.name(), cur, dep.name(), cx.prev_active(&dep).len());
705+
let mut remaining_candidates = RemainingCandidates::new(&candidates);
706+
let next = remaining_candidates.next(cx.prev_active(&dep), &cx.links);
697707

698708
// Alright, for each candidate that's gotten this far, it meets the
699709
// following requirements:
@@ -707,54 +717,55 @@ fn activate_deps_loop<'a>(mut cx: Context<'a>,
707717
// This means that we're going to attempt to activate each candidate in
708718
// turn. We could possibly fail to activate each candidate, so we try
709719
// each one in turn.
710-
let candidate = match next {
711-
Ok(candidate) => {
712-
// We have a candidate. Add an entry to the `backtrack_stack` so
713-
// we can try the next one if this one fails.
714-
if has_another {
715-
backtrack_stack.push(BacktrackFrame {
716-
cur,
717-
context_backup: Context::clone(&cx),
718-
deps_backup: <BinaryHeap<DepsFrame>>::clone(&remaining_deps),
719-
remaining_candidates,
720-
parent: Summary::clone(&parent),
721-
dep: Dependency::clone(&dep),
722-
features: Rc::clone(&features),
723-
});
724-
}
725-
candidate
726-
}
727-
Err(mut conflicting) => {
728-
// This dependency has no valid candidate. Backtrack until we
729-
// find a dependency that does have a candidate to try, and try
730-
// to activate that one. This resets the `remaining_deps` to
731-
// their state at the found level of the `backtrack_stack`.
732-
trace!("{}[{}]>{} -- no candidates", parent.name(), cur,
733-
dep.name());
734-
match find_candidate(&mut backtrack_stack,
735-
&mut cx,
736-
&mut remaining_deps,
737-
&mut parent,
738-
&mut cur,
739-
&mut dep,
740-
&mut features,
741-
&mut conflicting) {
742-
None => return Err(activation_error(&cx, registry, &parent,
743-
&dep,
744-
conflicting,
745-
&candidates, config)),
746-
Some(candidate) => candidate,
747-
}
748-
}
749-
};
720+
let (candidate, has_another) = next.or_else(|mut conflicting| {
721+
// This dependency has no valid candidate. Backtrack until we
722+
// find a dependency that does have a candidate to try, and try
723+
// to activate that one. This resets the `remaining_deps` to
724+
// their state at the found level of the `backtrack_stack`.
725+
trace!("{}[{}]>{} -- no candidates", parent.name(), cur, dep.name());
726+
find_candidate(
727+
&mut backtrack_stack,
728+
&mut cx,
729+
&mut remaining_deps,
730+
&mut parent,
731+
&mut cur,
732+
&mut dep,
733+
&mut features,
734+
&mut remaining_candidates,
735+
&mut conflicting,
736+
).ok_or_else(|| {
737+
activation_error(
738+
&cx,
739+
registry,
740+
&parent,
741+
&dep,
742+
conflicting,
743+
&candidates,
744+
config,
745+
)
746+
})
747+
})?;
748+
749+
// We have a candidate. Add an entry to the `backtrack_stack` so
750+
// we can try the next one if this one fails.
751+
if has_another {
752+
backtrack_stack.push(BacktrackFrame {
753+
cur,
754+
context_backup: Context::clone(&cx),
755+
deps_backup: <BinaryHeap<DepsFrame>>::clone(&remaining_deps),
756+
remaining_candidates,
757+
parent: Summary::clone(&parent),
758+
dep: Dependency::clone(&dep),
759+
features: Rc::clone(&features),
760+
});
761+
}
750762

751763
let method = Method::Required {
752764
dev_deps: false,
753765
features: &features,
754766
uses_default_features: dep.uses_default_features(),
755767
};
756-
trace!("{}[{}]>{} trying {}", parent.name(), cur, dep.name(),
757-
candidate.summary.version());
768+
trace!("{}[{}]>{} trying {}", parent.name(), cur, dep.name(), candidate.summary.version());
758769
let res = activate(&mut cx, registry, Some(&parent), candidate, &method)?;
759770
if let Some((frame, dur)) = res {
760771
remaining_deps.push(frame);
@@ -784,16 +795,11 @@ fn find_candidate<'a>(
784795
cur: &mut usize,
785796
dep: &mut Dependency,
786797
features: &mut Rc<Vec<String>>,
798+
remaining_candidates: &mut RemainingCandidates,
787799
conflicting_activations: &mut HashMap<PackageId, ConflictReason>,
788-
) -> Option<Candidate> {
800+
) -> Option<(Candidate, bool)> {
789801
while let Some(mut frame) = backtrack_stack.pop() {
790-
let (next, has_another) = {
791-
let prev_active = frame.context_backup.prev_active(&frame.dep);
792-
(
793-
frame.remaining_candidates.next(prev_active, &frame.context_backup.links),
794-
frame.remaining_candidates.clone().next(prev_active, &frame.context_backup.links).is_ok(),
795-
)
796-
};
802+
let next= frame.remaining_candidates.next(frame.context_backup.prev_active(&frame.dep), &frame.context_backup.links);
797803
if frame.context_backup.is_active(parent.package_id())
798804
&& conflicting_activations
799805
.iter()
@@ -802,23 +808,15 @@ fn find_candidate<'a>(
802808
{
803809
continue;
804810
}
805-
if let Ok(candidate) = next {
811+
if let Ok((candidate, has_another)) = next {
806812
*cur = frame.cur;
807-
if has_another {
808-
*cx = frame.context_backup.clone();
809-
*remaining_deps = frame.deps_backup.clone();
810-
*parent = frame.parent.clone();
811-
*dep = frame.dep.clone();
812-
*features = Rc::clone(&frame.features);
813-
backtrack_stack.push(frame);
814-
} else {
815-
*cx = frame.context_backup;
816-
*remaining_deps = frame.deps_backup;
817-
*parent = frame.parent;
818-
*dep = frame.dep;
819-
*features = frame.features;
820-
}
821-
return Some(candidate);
813+
*cx = frame.context_backup;
814+
*remaining_deps = frame.deps_backup;
815+
*parent = frame.parent;
816+
*dep = frame.dep;
817+
*features = frame.features;
818+
*remaining_candidates = frame.remaining_candidates;
819+
return Some((candidate, has_another));
822820
}
823821
}
824822
None

0 commit comments

Comments
 (0)