Skip to main content

cargo/core/resolver/
mod.rs

1//! Resolution of the entire dependency graph for a crate.
2//!
3//! This module implements the core logic in taking the world of crates and
4//! constraints and creating a resolved graph with locked versions for all
5//! crates and their dependencies. This is separate from the registry module
6//! which is more worried about discovering crates from various sources, this
7//! module just uses the Registry trait as a source to learn about crates from.
8//!
9//! Actually solving a constraint graph is an NP-hard problem. This algorithm
10//! is basically a nice heuristic to make sure we get roughly the best answer
11//! most of the time. The constraints that we're working with are:
12//!
13//! 1. Each crate can have any number of dependencies. Each dependency can
14//!    declare a version range that it is compatible with.
15//! 2. Crates can be activated with multiple version (e.g., show up in the
16//!    dependency graph twice) so long as each pairwise instance have
17//!    semver-incompatible versions.
18//!
19//! The algorithm employed here is fairly simple, we simply do a DFS, activating
20//! the "newest crate" (highest version) first and then going to the next
21//! option. The heuristics we employ are:
22//!
23//! * Never try to activate a crate version which is incompatible. This means we
24//!   only try crates which will actually satisfy a dependency and we won't ever
25//!   try to activate a crate that's semver compatible with something else
26//!   activated (as we're only allowed to have one) nor try to activate a crate
27//!   that has the same links attribute as something else
28//!   activated.
29//! * Always try to activate the highest version crate first. The default
30//!   dependency in Cargo (e.g., when you write `foo = "0.1.2"`) is
31//!   semver-compatible, so selecting the highest version possible will allow us
32//!   to hopefully satisfy as many dependencies at once.
33//!
34//! Beyond that, what's implemented below is just a naive backtracking version
35//! which should in theory try all possible combinations of dependencies and
36//! versions to see if one works. The first resolution that works causes
37//! everything to bail out immediately and return success, and only if *nothing*
38//! works do we actually return an error up the stack.
39//!
40//! Resolution is currently performed twice
41//! 1. With all features enabled (this is what gets saved to `Cargo.lock`)
42//! 2. With only the specific features the user selected on the command-line. Ideally this
43//!    run will get removed in the future when transitioning to the new feature resolver.
44//!
45//! A new feature-specific resolver was added in 2020 which adds more sophisticated feature
46//! resolution. It is located in the [`features`] module. The original dependency resolver still
47//! performs feature unification, as it can help reduce the dependencies it has to consider during
48//! resolution (rather than assuming every optional dependency of every package is enabled).
49//! Checking if a feature is enabled must go through the new feature resolver.
50//!
51//! ## Performance
52//!
53//! Note that this is a relatively performance-critical portion of Cargo. The
54//! data that we're processing is proportional to the size of the dependency
55//! graph, which can often be quite large (e.g., take a look at Servo). To make
56//! matters worse the DFS algorithm we're implemented is inherently quite
57//! inefficient. When we add the requirement of backtracking on top it means
58//! that we're implementing something that probably shouldn't be allocating all
59//! over the place.
60
61use crate::util::data_structures::{HashMap, HashSet};
62use rustc_hash::FxBuildHasher;
63use std::collections::BTreeMap;
64use std::rc::Rc;
65use std::time::{Duration, Instant};
66use tracing::{debug, trace};
67
68use crate::core::PackageIdSpec;
69use crate::core::{Dependency, PackageId, Registry, Summary};
70use crate::util::context::GlobalContext;
71use crate::util::errors::CargoResult;
72use crate::util::network::PollExt;
73
74use self::context::ResolverContext;
75use self::dep_cache::RegistryQueryer;
76use self::features::RequestedFeatures;
77use self::types::{ConflictMap, ConflictReason, DepsFrame};
78use self::types::{FeaturesSet, RcVecIter, RemainingDeps, ResolverProgress};
79
80pub use self::errors::{ActivateError, ActivateResult, ResolveError};
81pub use self::features::{CliFeatures, ForceAllTargets, HasDevUnits};
82pub use self::resolve::{Resolve, ResolveVersion};
83pub use self::types::{ResolveBehavior, ResolveOpts};
84pub use self::version_prefs::PublishAgePolicy;
85pub use self::version_prefs::PublishAgeViolation;
86pub use self::version_prefs::VersionOrdering;
87pub use self::version_prefs::VersionPreferences;
88
89mod conflict_cache;
90mod context;
91mod dep_cache;
92pub(crate) mod encode;
93pub(crate) mod errors;
94pub mod features;
95mod resolve;
96mod types;
97mod version_prefs;
98
99/// Builds the list of all packages required to build the first argument.
100///
101/// * `summaries` - the list of package summaries along with how to resolve
102///   their features. This is a list of all top-level packages that are intended
103///   to be part of the lock file (resolve output). These typically are a list
104///   of all workspace members.
105///
106/// * `replacements` - this is a list of `[replace]` directives found in the
107///   root of the workspace. The list here is a `PackageIdSpec` of what to
108///   replace and a `Dependency` to replace that with. In general it's not
109///   recommended to use `[replace]` any more and use `[patch]` instead, which
110///   is supported elsewhere.
111///
112/// * `registry` - this is the source from which all package summaries are
113///   loaded. It's expected that this is extensively configured ahead of time
114///   and is idempotent with our requests to it (aka returns the same results
115///   for the same query every time). Typically this is an instance of a
116///   `PackageRegistry`.
117///
118/// * `version_prefs` - this represents a preference for some versions over others,
119///   based on the lock file or other reasons such as `[patch]`es.
120///
121/// * `resolve_version` - this controls how the lockfile will be serialized.
122///
123/// * `config` - a location to print warnings and such, or `None` if no warnings
124///   should be printed
125#[tracing::instrument(skip_all)]
126pub fn resolve(
127    summaries: &[(Summary, ResolveOpts)],
128    replacements: &[(PackageIdSpec, Dependency)],
129    registry: &impl Registry,
130    version_prefs: &VersionPreferences,
131    resolve_version: ResolveVersion,
132    gctx: Option<&GlobalContext>,
133) -> CargoResult<Resolve> {
134    let first_version = match gctx {
135        Some(config) if config.cli_unstable().direct_minimal_versions => {
136            Some(VersionOrdering::MinimumVersionsFirst)
137        }
138        _ => None,
139    };
140    let mut registry = RegistryQueryer::new(registry, replacements, version_prefs);
141
142    // Global cache of the reasons for each time we backtrack.
143    let mut past_conflicting_activations = conflict_cache::ConflictCache::new();
144
145    let resolver_ctx = loop {
146        let resolver_ctx = activate_deps_loop(
147            &mut registry,
148            summaries,
149            first_version,
150            gctx,
151            &mut past_conflicting_activations,
152        )?;
153        if registry.wait()? {
154            break resolver_ctx;
155        }
156    };
157
158    let mut cksums = HashMap::default();
159    for (summary, _) in resolver_ctx.activations.values() {
160        let cksum = summary.checksum().map(|s| s.to_string());
161        cksums.insert(summary.package_id(), cksum);
162    }
163    let graph = resolver_ctx.graph();
164    let replacements = resolver_ctx.resolve_replacements(&registry);
165    let features = resolver_ctx
166        .resolve_features
167        .iter()
168        .map(|(k, v)| (*k, v.iter().cloned().collect()))
169        .collect();
170    let summaries = resolver_ctx
171        .activations
172        .into_iter()
173        .map(|(_key, (summary, _age))| (summary.package_id(), summary))
174        .collect();
175    let resolve = Resolve::new(
176        graph,
177        replacements,
178        features,
179        cksums,
180        BTreeMap::new(),
181        Vec::new(),
182        resolve_version,
183        summaries,
184    );
185
186    check_cycles(&resolve)?;
187    check_duplicate_pkgs_in_lockfile(&resolve)?;
188    trace!("resolved: {:?}", resolve);
189
190    Ok(resolve)
191}
192
193/// Recursively activates the dependencies for `summaries`, in depth-first order,
194/// backtracking across possible candidates for each dependency as necessary.
195///
196/// If all dependencies can be activated and resolved to a version in the
197/// dependency graph, `cx` is returned.
198fn activate_deps_loop(
199    registry: &mut RegistryQueryer<'_, impl Registry>,
200    summaries: &[(Summary, ResolveOpts)],
201    first_version: Option<VersionOrdering>,
202    gctx: Option<&GlobalContext>,
203    past_conflicting_activations: &mut conflict_cache::ConflictCache,
204) -> CargoResult<ResolverContext> {
205    let mut resolver_ctx = ResolverContext::new();
206    let mut backtrack_stack = Vec::new();
207    let mut remaining_deps = RemainingDeps::new();
208
209    // Activate all the initial summaries to kick off some work.
210    for (summary, opts) in summaries {
211        debug!("initial activation: {}", summary.package_id());
212        let res = activate(
213            &mut resolver_ctx,
214            registry,
215            None,
216            summary.clone(),
217            first_version,
218            opts,
219        );
220        match res {
221            Ok(Some((frame, _))) => remaining_deps.push(frame),
222            Ok(None) => (),
223            Err(ActivateError::Fatal(e)) => return Err(e),
224            Err(ActivateError::Conflict(_, _)) => panic!("bad error from activate"),
225        }
226    }
227
228    let mut printed = ResolverProgress::new();
229
230    // Main resolution loop, this is the workhorse of the resolution algorithm.
231    //
232    // You'll note that a few stacks are maintained on the side, which might
233    // seem odd when this algorithm looks like it could be implemented
234    // recursively. While correct, this is implemented iteratively to avoid
235    // blowing the stack (the recursion depth is proportional to the size of the
236    // input).
237    //
238    // The general sketch of this loop is to run until there are no dependencies
239    // left to activate, and for each dependency to attempt to activate all of
240    // its own dependencies in turn. The `backtrack_stack` is a side table of
241    // backtracking states where if we hit an error we can return to in order to
242    // attempt to continue resolving.
243    while let Some((just_here_for_the_error_messages, frame)) =
244        remaining_deps.pop_most_constrained()
245    {
246        let (mut parent, (mut dep, candidates, mut features)) = frame;
247
248        // If we spend a lot of time here (we shouldn't in most cases) then give
249        // a bit of a visual indicator as to what we're doing.
250        printed.shell_status(gctx)?;
251
252        trace!(
253            "{}[{}]>{} {} candidates",
254            parent.name(),
255            resolver_ctx.age,
256            dep.package_name(),
257            candidates.len()
258        );
259
260        let just_here_for_the_error_messages = just_here_for_the_error_messages
261            && past_conflicting_activations
262                .conflicting(&resolver_ctx, &dep)
263                .is_some();
264
265        let mut remaining_candidates = RemainingCandidates::new(&candidates);
266
267        // `conflicting_activations` stores all the reasons we were unable to
268        // activate candidates. One of these reasons will have to go away for
269        // backtracking to find a place to restart. It is also the list of
270        // things to explain in the error message if we fail to resolve.
271        //
272        // This is a map of package ID to a reason why that packaged caused a
273        // conflict for us.
274        let mut conflicting_activations = ConflictMap::new();
275
276        // When backtracking we don't fully update `conflicting_activations`
277        // especially for the cases that we didn't make a backtrack frame in the
278        // first place. This `backtracked` var stores whether we are continuing
279        // from a restored backtrack frame so that we can skip caching
280        // `conflicting_activations` in `past_conflicting_activations`
281        let mut backtracked = false;
282
283        loop {
284            let next = remaining_candidates.next(&mut conflicting_activations, &resolver_ctx);
285
286            let (candidate, has_another) = next.ok_or(()).or_else(|_| {
287                // If we get here then our `remaining_candidates` was just
288                // exhausted, so `dep` failed to activate.
289                //
290                // It's our job here to backtrack, if possible, and find a
291                // different candidate to activate. If we can't find any
292                // candidates whatsoever then it's time to bail entirely.
293                trace!(
294                    "{}[{}]>{} -- no candidates",
295                    parent.name(),
296                    resolver_ctx.age,
297                    dep.package_name()
298                );
299
300                // Use our list of `conflicting_activations` to add to our
301                // global list of past conflicting activations, effectively
302                // globally poisoning `dep` if `conflicting_activations` ever
303                // shows up again. We'll use the `past_conflicting_activations`
304                // below to determine if a dependency is poisoned and skip as
305                // much work as possible.
306                //
307                // If we're only here for the error messages then there's no
308                // need to try this as this dependency is already known to be
309                // bad.
310                //
311                // As we mentioned above with the `backtracked` variable if this
312                // local is set to `true` then our `conflicting_activations` may
313                // not be right, so we can't push into our global cache.
314                let mut generalize_conflicting_activations = None;
315                if !just_here_for_the_error_messages && !backtracked {
316                    past_conflicting_activations.insert(&dep, &conflicting_activations);
317                    if let Some(c) = generalize_conflicting(
318                        &resolver_ctx,
319                        registry,
320                        past_conflicting_activations,
321                        &parent,
322                        &dep,
323                        &conflicting_activations,
324                    ) {
325                        generalize_conflicting_activations = Some(c);
326                    }
327                }
328
329                match find_candidate(
330                    &resolver_ctx,
331                    &mut backtrack_stack,
332                    &parent,
333                    backtracked,
334                    generalize_conflicting_activations
335                        .as_ref()
336                        .unwrap_or(&conflicting_activations),
337                ) {
338                    Some((candidate, has_another, frame)) => {
339                        // Reset all of our local variables used with the
340                        // contents of `frame` to complete our backtrack.
341                        resolver_ctx = frame.context;
342                        remaining_deps = frame.remaining_deps;
343                        remaining_candidates = frame.remaining_candidates;
344                        parent = frame.parent;
345                        dep = frame.dep;
346                        features = frame.features;
347                        conflicting_activations = frame.conflicting_activations;
348                        backtracked = true;
349                        Ok((candidate, has_another))
350                    }
351                    None => {
352                        debug!("no candidates found");
353                        Err(errors::activation_error(
354                            &resolver_ctx,
355                            registry.registry(),
356                            registry.version_prefs(),
357                            &parent,
358                            &dep,
359                            &conflicting_activations,
360                            &candidates,
361                            gctx,
362                        ))
363                    }
364                }
365            })?;
366
367            // If we're only here for the error messages then we know that this
368            // activation will fail one way or another. To that end if we've got
369            // more candidates we want to fast-forward to the last one as
370            // otherwise we'll just backtrack here anyway (helping us to skip
371            // some work).
372            if just_here_for_the_error_messages && !backtracked && has_another {
373                continue;
374            }
375
376            // We have a `candidate`. Create a `BacktrackFrame` so we can add it
377            // to the `backtrack_stack` later if activation succeeds.
378            //
379            // Note that if we don't actually have another candidate then there
380            // will be nothing to backtrack to so we skip construction of the
381            // frame. This is a relatively important optimization as a number of
382            // the `clone` calls below can be quite expensive, so we avoid them
383            // if we can.
384            let backtrack = if has_another {
385                Some(BacktrackFrame {
386                    context: ResolverContext::clone(&resolver_ctx),
387                    remaining_deps: remaining_deps.clone(),
388                    remaining_candidates: remaining_candidates.clone(),
389                    parent: Summary::clone(&parent),
390                    dep: Dependency::clone(&dep),
391                    features: Rc::clone(&features),
392                    conflicting_activations: conflicting_activations.clone(),
393                })
394            } else {
395                None
396            };
397
398            let pid = candidate.package_id();
399            let opts = ResolveOpts {
400                dev_deps: false,
401                features: RequestedFeatures::DepFeatures {
402                    features: Rc::clone(&features),
403                    uses_default_features: dep.uses_default_features(),
404                },
405            };
406            trace!(
407                "{}[{}]>{} trying {}",
408                parent.name(),
409                resolver_ctx.age,
410                dep.package_name(),
411                candidate.version()
412            );
413            let first_version = None; // this is an indirect dependency
414            let res = activate(
415                &mut resolver_ctx,
416                registry,
417                Some((&parent, &dep)),
418                candidate,
419                first_version,
420                &opts,
421            );
422
423            let successfully_activated = match res {
424                // Success! We've now activated our `candidate` in our context
425                // and we're almost ready to move on. We may want to scrap this
426                // frame in the end if it looks like it's not going to end well,
427                // so figure that out here.
428                Ok(Some((mut frame, dur))) => {
429                    printed.elapsed(dur);
430
431                    // Our `frame` here is a new package with its own list of
432                    // dependencies. Do a sanity check here of all those
433                    // dependencies by cross-referencing our global
434                    // `past_conflicting_activations`. Recall that map is a
435                    // global cache which lists sets of packages where, when
436                    // activated, the dependency is unresolvable.
437                    //
438                    // If any our frame's dependencies fit in that bucket,
439                    // aka known unresolvable, then we extend our own set of
440                    // conflicting activations with theirs. We can do this
441                    // because the set of conflicts we found implies the
442                    // dependency can't be activated which implies that we
443                    // ourselves can't be activated, so we know that they
444                    // conflict with us.
445                    let mut has_past_conflicting_dep = just_here_for_the_error_messages;
446                    if !has_past_conflicting_dep {
447                        if let Some(conflicting) =
448                            frame
449                                .remaining_siblings
450                                .remaining()
451                                .find_map(|(new_dep, _, _)| {
452                                    past_conflicting_activations.conflicting(&resolver_ctx, new_dep)
453                                })
454                        {
455                            // If one of our deps is known unresolvable
456                            // then we will not succeed.
457                            // How ever if we are part of the reason that
458                            // one of our deps conflicts then
459                            // we can make a stronger statement
460                            // because we will definitely be activated when
461                            // we try our dep.
462                            conflicting_activations.extend(
463                                conflicting
464                                    .iter()
465                                    .filter(|&(p, _)| p != &pid)
466                                    .map(|(&p, r)| (p, r.clone())),
467                            );
468
469                            has_past_conflicting_dep = true;
470                        }
471                    }
472                    // If any of `remaining_deps` are known unresolvable with
473                    // us activated, then we extend our own set of
474                    // conflicting activations with theirs and its parent. We can do this
475                    // because the set of conflicts we found implies the
476                    // dependency can't be activated which implies that we
477                    // ourselves are incompatible with that dep, so we know that deps
478                    // parent conflict with us.
479                    if !has_past_conflicting_dep {
480                        if let Some(known_related_bad_deps) =
481                            past_conflicting_activations.dependencies_conflicting_with(pid)
482                        {
483                            if let Some((other_parent, conflict)) = remaining_deps
484                                .iter()
485                                // for deps related to us
486                                .filter(|(_, other_dep)| known_related_bad_deps.contains(other_dep))
487                                .filter_map(|(other_parent, other_dep)| {
488                                    past_conflicting_activations
489                                        .find_conflicting(&resolver_ctx, &other_dep, Some(pid))
490                                        .map(|con| (other_parent, con))
491                                })
492                                .next()
493                            {
494                                let rel = conflict.get(&pid).unwrap().clone();
495
496                                // The conflict we found is
497                                // "other dep will not succeed if we are activated."
498                                // We want to add
499                                // "our dep will not succeed if other dep is in remaining_deps"
500                                // but that is not how the cache is set up.
501                                // So we add the less general but much faster,
502                                // "our dep will not succeed if other dep's parent is activated".
503                                conflicting_activations.extend(
504                                    conflict
505                                        .iter()
506                                        .filter(|&(p, _)| p != &pid)
507                                        .map(|(&p, r)| (p, r.clone())),
508                                );
509                                conflicting_activations.insert(other_parent, rel);
510                                has_past_conflicting_dep = true;
511                            }
512                        }
513                    }
514
515                    // Ok if we're in a "known failure" state for this frame we
516                    // may want to skip it altogether though. We don't want to
517                    // skip it though in the case that we're displaying error
518                    // messages to the user!
519                    //
520                    // Here we need to figure out if the user will see if we
521                    // skipped this candidate (if it's known to fail, aka has a
522                    // conflicting dep and we're the last candidate). If we're
523                    // here for the error messages, we can't skip it (but we can
524                    // prune extra work). If we don't have any candidates in our
525                    // backtrack stack then we're the last line of defense, so
526                    // we'll want to present an error message for sure.
527                    let activate_for_error_message = has_past_conflicting_dep && !has_another && {
528                        just_here_for_the_error_messages || {
529                            find_candidate(
530                                &resolver_ctx,
531                                &mut backtrack_stack.clone(),
532                                &parent,
533                                backtracked,
534                                &conflicting_activations,
535                            )
536                            .is_none()
537                        }
538                    };
539
540                    // If we're only here for the error messages then we know
541                    // one of our candidate deps will fail, meaning we will
542                    // fail and that none of the backtrack frames will find a
543                    // candidate that will help. Consequently let's clean up the
544                    // no longer needed backtrack frames.
545                    if activate_for_error_message {
546                        backtrack_stack.clear();
547                    }
548
549                    // If we don't know for a fact that we'll fail or if we're
550                    // just here for the error message then we push this frame
551                    // onto our list of to-be-resolve, which will generate more
552                    // work for us later on.
553                    //
554                    // Otherwise we're guaranteed to fail and were not here for
555                    // error messages, so we skip work and don't push anything
556                    // onto our stack.
557                    frame.just_for_error_messages = has_past_conflicting_dep;
558                    if !has_past_conflicting_dep || activate_for_error_message {
559                        remaining_deps.push(frame);
560                        true
561                    } else {
562                        trace!(
563                            "{}[{}]>{} skipping {} ",
564                            parent.name(),
565                            resolver_ctx.age,
566                            dep.package_name(),
567                            pid.version()
568                        );
569                        false
570                    }
571                }
572
573                // This candidate's already activated, so there's no extra work
574                // for us to do. Let's keep going.
575                Ok(None) => true,
576
577                // We failed with a super fatal error (like a network error), so
578                // bail out as quickly as possible as we can't reliably
579                // backtrack from errors like these
580                Err(ActivateError::Fatal(e)) => return Err(e),
581
582                // We failed due to a bland conflict, bah! Record this in our
583                // frame's list of conflicting activations as to why this
584                // candidate failed, and then move on.
585                Err(ActivateError::Conflict(id, reason)) => {
586                    conflicting_activations.insert(id, reason);
587                    false
588                }
589            };
590
591            // If we've successfully activated then save off the backtrack frame
592            // if one was created, and otherwise break out of the inner
593            // activation loop as we're ready to move to the next dependency
594            if successfully_activated {
595                backtrack_stack.extend(backtrack);
596                break;
597            }
598
599            // We've failed to activate this dependency, oh dear! Our call to
600            // `activate` above may have altered our `cx` local variable, so
601            // restore it back if we've got a backtrack frame.
602            //
603            // If we don't have a backtrack frame then we're just using the `cx`
604            // for error messages anyway so we can live with a little
605            // imprecision.
606            if let Some(b) = backtrack {
607                resolver_ctx = b.context;
608            }
609        }
610
611        // Ok phew, that loop was a big one! If we've broken out then we've
612        // successfully activated a candidate. Our stacks are all in place that
613        // we're ready to move on to the next dependency that needs activation,
614        // so loop back to the top of the function here.
615    }
616
617    Ok(resolver_ctx)
618}
619
620/// Attempts to activate the summary `candidate` in the context `cx`.
621///
622/// This function will pull dependency summaries from the registry provided, and
623/// the dependencies of the package will be determined by the `opts` provided.
624/// If `candidate` was activated, this function returns the dependency frame to
625/// iterate through next.
626fn activate(
627    cx: &mut ResolverContext,
628    registry: &mut RegistryQueryer<'_, impl Registry>,
629    parent: Option<(&Summary, &Dependency)>,
630    candidate: Summary,
631    first_version: Option<VersionOrdering>,
632    opts: &ResolveOpts,
633) -> ActivateResult<Option<(DepsFrame, Duration)>> {
634    let candidate_pid = candidate.package_id();
635    cx.age += 1;
636    if let Some((parent, dep)) = parent {
637        let parent_pid = parent.package_id();
638        // add an edge from candidate to parent in the parents graph
639        cx.parents
640            .link(candidate_pid, parent_pid)
641            // and associate dep with that edge
642            .insert(dep.clone());
643    }
644
645    let activated = cx.flag_activated(&candidate, opts, parent)?;
646
647    let candidate = match registry.replacement_summary(candidate_pid) {
648        Some(replace) => {
649            // Note the `None` for parent here since `[replace]` is a bit wonky
650            // and doesn't activate the same things that `[patch]` typically
651            // does. TBH it basically cause panics in the test suite if
652            // `parent` is passed through here and `[replace]` is otherwise
653            // on life support so it's not critical to fix bugs anyway per se.
654            if cx.flag_activated(&replace, opts, None)? && activated {
655                return Ok(None);
656            }
657            trace!(
658                "activating {} (replacing {})",
659                replace.package_id(),
660                candidate_pid
661            );
662            replace.clone()
663        }
664        None => {
665            if activated {
666                return Ok(None);
667            }
668            trace!("activating {}", candidate_pid);
669            candidate
670        }
671    };
672
673    let now = Instant::now();
674    let (used_features, deps) = &*registry.build_deps(
675        cx,
676        parent.map(|p| p.0.package_id()),
677        &candidate,
678        opts,
679        first_version,
680    )?;
681
682    // Record what list of features is active for this package.
683    if !used_features.is_empty() {
684        Rc::make_mut(
685            cx.resolve_features
686                .entry(candidate.package_id())
687                .or_default(),
688        )
689        .extend(used_features);
690    }
691
692    let frame = DepsFrame {
693        parent: candidate,
694        just_for_error_messages: false,
695        remaining_siblings: RcVecIter::new(Rc::clone(deps)),
696    };
697    Ok(Some((frame, now.elapsed())))
698}
699
700#[derive(Clone)]
701struct BacktrackFrame {
702    context: ResolverContext,
703    remaining_deps: RemainingDeps,
704    remaining_candidates: RemainingCandidates,
705    parent: Summary,
706    dep: Dependency,
707    features: FeaturesSet,
708    conflicting_activations: ConflictMap,
709}
710
711/// A helper "iterator" used to extract candidates within a current `Context` of
712/// a dependency graph.
713///
714/// This struct doesn't literally implement the `Iterator` trait (requires a few
715/// more inputs) but in general acts like one. Each `RemainingCandidates` is
716/// created with a list of candidates to choose from. When attempting to iterate
717/// over the list of candidates only *valid* candidates are returned. Validity
718/// is defined within a `Context`.
719///
720/// Candidates passed to `new` may not be returned from `next` as they could be
721/// filtered out, and as they are filtered the causes will be added to `conflicting_prev_active`.
722#[derive(Clone)]
723struct RemainingCandidates {
724    remaining: RcVecIter<Summary>,
725    // This is an inlined peekable generator
726    has_another: Option<Summary>,
727}
728
729impl RemainingCandidates {
730    fn new(candidates: &Rc<Vec<Summary>>) -> RemainingCandidates {
731        RemainingCandidates {
732            remaining: RcVecIter::new(Rc::clone(candidates)),
733            has_another: None,
734        }
735    }
736
737    /// Attempts to find another candidate to check from this list.
738    ///
739    /// This method will attempt to move this iterator forward, returning a
740    /// candidate that's possible to activate. The `cx` argument is the current
741    /// context which determines validity for candidates returned, and the `dep`
742    /// is the dependency listing that we're activating for.
743    ///
744    /// If successful a `(Candidate, bool)` pair will be returned. The
745    /// `Candidate` is the candidate to attempt to activate, and the `bool` is
746    /// an indicator of whether there are remaining candidates to try of if
747    /// we've reached the end of iteration.
748    ///
749    /// If we've reached the end of the iterator here then `Err` will be
750    /// returned. The error will contain a map of package ID to conflict reason,
751    /// where each package ID caused a candidate to be filtered out from the
752    /// original list for the reason listed.
753    fn next(
754        &mut self,
755        conflicting_prev_active: &mut ConflictMap,
756        cx: &ResolverContext,
757    ) -> Option<(Summary, bool)> {
758        for b in self.remaining.iter() {
759            let b_id = b.package_id();
760
761            // The condition for being a valid candidate relies on
762            // semver. Cargo dictates that you can't duplicate multiple
763            // semver-compatible versions of a crate. For example we can't
764            // simultaneously activate `foo 1.0.2` and `foo 1.2.0`. We can,
765            // however, activate `1.0.2` and `2.0.0`.
766            //
767            // Here we throw out our candidate if it's *compatible*, yet not
768            // equal, to all previously activated versions.
769            if let Some((a, _)) = cx.activations.get(&b_id.as_activations_key()) {
770                if a != b {
771                    conflicting_prev_active
772                        .entry(a.package_id())
773                        .or_insert(ConflictReason::Semver);
774                    continue;
775                }
776            }
777
778            // Otherwise the `links` key in the manifest dictates that there's only one
779            // package in a dependency graph, globally, with that particular
780            // `links` key. If this candidate links to something that's already
781            // linked to by a different package then we've gotta skip this.
782            if let Some(link) = b.links() {
783                if let Some(&a) = cx.links.get(&link) {
784                    if a != b_id {
785                        conflicting_prev_active
786                            .entry(a)
787                            .or_insert_with(|| ConflictReason::Links(link));
788                        continue;
789                    }
790                }
791            }
792
793            // Well if we made it this far then we've got a valid dependency. We
794            // want this iterator to be inherently "peekable" so we don't
795            // necessarily return the item just yet. Instead we stash it away to
796            // get returned later, and if we replaced something then that was
797            // actually the candidate to try first so we return that.
798            if let Some(r) = self.has_another.replace(b.clone()) {
799                return Some((r, true));
800            }
801        }
802
803        // Alright we've entirely exhausted our list of candidates. If we've got
804        // something stashed away return that here (also indicating that there's
805        // nothing else).
806        self.has_another.take().map(|r| (r, false))
807    }
808}
809
810/// Attempts to find a new conflict that allows a `find_candidate` better then the input one.
811/// It will add the new conflict to the cache if one is found.
812fn generalize_conflicting(
813    cx: &ResolverContext,
814    registry: &mut RegistryQueryer<'_, impl Registry>,
815    past_conflicting_activations: &mut conflict_cache::ConflictCache,
816    parent: &Summary,
817    dep: &Dependency,
818    conflicting_activations: &ConflictMap,
819) -> Option<ConflictMap> {
820    // We need to determine the `ContextAge` that this `conflicting_activations` will jump to, and why.
821    let (backtrack_critical_age, backtrack_critical_id) = shortcircuit_max(
822        conflicting_activations
823            .keys()
824            .map(|&c| cx.is_active(c).map(|a| (a, c))),
825    )?;
826    let backtrack_critical_reason: ConflictReason =
827        conflicting_activations[&backtrack_critical_id].clone();
828
829    if cx
830        .parents
831        .is_path_from_to(&parent.package_id(), &backtrack_critical_id)
832    {
833        // We are a descendant of the trigger of the problem.
834        // The best generalization of this is to let things bubble up
835        // and let `backtrack_critical_id` figure this out.
836        return None;
837    }
838    // What parents does that critical activation have
839    for (critical_parent, critical_parents_deps) in
840        cx.parents.edges(&backtrack_critical_id).filter(|(p, _)| {
841            // it will only help backjump further if it is older then the critical_age
842            cx.is_active(**p).expect("parent not currently active!?") < backtrack_critical_age
843        })
844    {
845        for critical_parents_dep in critical_parents_deps.iter() {
846            // We only want `first_version.is_some()` for direct dependencies of workspace
847            // members which isn't the case here as this has a `parent`
848            let first_version = None;
849            // A dep is equivalent to one of the things it can resolve to.
850            // Thus, if all the things it can resolve to have already ben determined
851            // to be conflicting, then we can just say that we conflict with the parent.
852            if let Some(others) = registry
853                .query(critical_parents_dep, first_version)
854                .expect("an already used dep now pending!?")
855                .expect("an already used dep now error!?")
856                .iter()
857                .rev() // the last one to be tried is the least likely to be in the cache, so start with that.
858                .map(|other| {
859                    past_conflicting_activations
860                        .find(
861                            dep,
862                            &|id| {
863                                if id == other.package_id() {
864                                    // we are imagining that we used other instead
865                                    Some(backtrack_critical_age)
866                                } else {
867                                    cx.is_active(id)
868                                }
869                            },
870                            Some(other.package_id()),
871                            // we only care about things that are newer then critical_age
872                            backtrack_critical_age,
873                        )
874                        .map(|con| (other.package_id(), con))
875                })
876                .collect::<Option<Vec<(PackageId, &ConflictMap)>>>()
877            {
878                let mut con = conflicting_activations.clone();
879                // It is always valid to combine previously inserted conflicts.
880                // A, B are both known bad states each that can never be activated.
881                // A + B is redundant but can't be activated, as if
882                // A + B is active then A is active and we know that is not ok.
883                for (_, other) in &others {
884                    con.extend(other.iter().map(|(&id, re)| (id, re.clone())));
885                }
886                // Now that we have this combined conflict, we can do a substitution:
887                // A dep is equivalent to one of the things it can resolve to.
888                // So we can remove all the things that it resolves to and replace with the parent.
889                for (other_id, _) in &others {
890                    con.remove(other_id);
891                }
892                con.insert(*critical_parent, backtrack_critical_reason);
893
894                if cfg!(debug_assertions) {
895                    // the entire point is to find an older conflict, so let's make sure we did
896                    let new_age = con
897                        .keys()
898                        .map(|&c| cx.is_active(c).expect("not currently active!?"))
899                        .max()
900                        .unwrap();
901                    assert!(
902                        new_age < backtrack_critical_age,
903                        "new_age {} < backtrack_critical_age {}",
904                        new_age,
905                        backtrack_critical_age
906                    );
907                }
908                past_conflicting_activations.insert(dep, &con);
909                return Some(con);
910            }
911        }
912    }
913    None
914}
915
916/// Returns Some of the largest item in the iterator.
917/// Returns None if any of the items are None or the iterator is empty.
918fn shortcircuit_max<I: Ord>(iter: impl Iterator<Item = Option<I>>) -> Option<I> {
919    let mut out = None;
920    for i in iter {
921        if i.is_none() {
922            return None;
923        }
924        out = std::cmp::max(out, i);
925    }
926    out
927}
928
929/// Looks through the states in `backtrack_stack` for dependencies with
930/// remaining candidates. For each one, also checks if rolling back
931/// could change the outcome of the failed resolution that caused backtracking
932/// in the first place. Namely, if we've backtracked past the parent of the
933/// failed dep, or any of the packages flagged as giving us trouble in
934/// `conflicting_activations`.
935///
936/// Read <https://github.com/rust-lang/cargo/pull/4834>
937/// For several more detailed explanations of the logic here.
938fn find_candidate(
939    cx: &ResolverContext,
940    backtrack_stack: &mut Vec<BacktrackFrame>,
941    parent: &Summary,
942    backtracked: bool,
943    conflicting_activations: &ConflictMap,
944) -> Option<(Summary, bool, BacktrackFrame)> {
945    // When we're calling this method we know that `parent` failed to
946    // activate. That means that some dependency failed to get resolved for
947    // whatever reason. Normally, that means that all of those reasons
948    // (plus maybe some extras) are listed in `conflicting_activations`.
949    //
950    // The abnormal situations are things that do not put all of the reasons in `conflicting_activations`:
951    // If we backtracked we do not know how our `conflicting_activations` related to
952    // the cause of that backtrack, so we do not update it.
953    let age = if !backtracked {
954        // we don't have abnormal situations. So we can ask `cx` for how far back we need to go.
955        // If the `conflicting_activations` does not apply to `cx`,
956        // we will just fall back to laboriously trying all possibilities witch
957        // will give us the correct answer.
958        cx.is_conflicting(Some(parent.package_id()), conflicting_activations)
959    } else {
960        None
961    };
962    let mut new_frame = None;
963    if let Some(age) = age {
964        while let Some(frame) = backtrack_stack.pop() {
965            // If all members of `conflicting_activations` are still
966            // active in this back up we know that we're guaranteed to not actually
967            // make any progress. As a result if we hit this condition we can
968            // completely skip this backtrack frame and move on to the next.
969
970            // Above we use `cx` to determine if this is going to be conflicting.
971            // But lets just double check if the `pop`ed frame agrees.
972            let frame_too_new = frame.context.age >= age;
973            debug_assert!(
974                frame
975                    .context
976                    .is_conflicting(Some(parent.package_id()), conflicting_activations)
977                    == frame_too_new.then_some(age)
978            );
979
980            if !frame_too_new {
981                new_frame = Some(frame);
982                break;
983            }
984            trace!(
985                "{} = \"{}\" skip as not solving {}: {:?}",
986                frame.dep.package_name(),
987                frame.dep.version_req(),
988                parent.package_id(),
989                conflicting_activations
990            );
991        }
992    } else {
993        // If we're here then we are in abnormal situations and need to just go one frame at a time.
994        new_frame = backtrack_stack.pop();
995    }
996
997    new_frame.map(|mut frame| {
998        let (candidate, has_another) = frame
999            .remaining_candidates
1000            .next(&mut frame.conflicting_activations, &frame.context)
1001            .expect("why did we save a frame that has no next?");
1002        (candidate, has_another, frame)
1003    })
1004}
1005
1006fn check_cycles(resolve: &Resolve) -> CargoResult<()> {
1007    // Perform a simple cycle check by visiting all nodes.
1008    // We visit each node at most once and we keep
1009    // track of the path through the graph as we walk it. If we walk onto the
1010    // same node twice that's a cycle.
1011    let mut checked = HashSet::with_capacity_and_hasher(resolve.len(), FxBuildHasher::default());
1012    let mut path = Vec::with_capacity(4);
1013    let mut visited = HashSet::with_capacity_and_hasher(4, FxBuildHasher::default());
1014    for pkg in resolve.iter() {
1015        if !checked.contains(&pkg) {
1016            visit(&resolve, pkg, &mut visited, &mut path, &mut checked)?
1017        }
1018    }
1019    return Ok(());
1020
1021    fn visit(
1022        resolve: &Resolve,
1023        id: PackageId,
1024        visited: &mut HashSet<PackageId>,
1025        path: &mut Vec<PackageId>,
1026        checked: &mut HashSet<PackageId>,
1027    ) -> CargoResult<()> {
1028        if !visited.insert(id) {
1029            // We found a cycle and need to construct an error. Performance is no longer top priority.
1030            let iter = path.iter().rev().scan(id, |child, parent| {
1031                let dep = resolve.transitive_deps_not_replaced(*parent).find_map(
1032                    |(dep_id, transitive_dep)| {
1033                        (*child == dep_id || Some(*child) == resolve.replacement(dep_id))
1034                            .then_some(transitive_dep)
1035                    },
1036                );
1037                *child = *parent;
1038                Some((parent, dep))
1039            });
1040            let iter = std::iter::once((&id, None)).chain(iter);
1041            let describe_path = errors::describe_path(iter);
1042            anyhow::bail!(
1043                "cyclic package dependency: package `{id}` depends on itself. Cycle:\n{describe_path}"
1044            );
1045        }
1046
1047        if checked.insert(id) {
1048            path.push(id);
1049            for (dep_id, _transitive_dep) in resolve.transitive_deps_not_replaced(id) {
1050                visit(resolve, dep_id, visited, path, checked)?;
1051                if let Some(replace_id) = resolve.replacement(dep_id) {
1052                    visit(resolve, replace_id, visited, path, checked)?;
1053                }
1054            }
1055            path.pop();
1056        }
1057
1058        visited.remove(&id);
1059        Ok(())
1060    }
1061}
1062
1063/// Checks that packages are unique when written to lock file.
1064///
1065/// When writing package ID's to lock file, we apply lossy encoding. In
1066/// particular, we don't store paths of path dependencies. That means that
1067/// *different* packages may collide in the lock file, hence this check.
1068fn check_duplicate_pkgs_in_lockfile(resolve: &Resolve) -> CargoResult<()> {
1069    let mut unique_pkg_ids = HashMap::default();
1070    let state = encode::EncodeState::new(resolve);
1071    for pkg_id in resolve.iter() {
1072        let encodable_pkd_id = encode::encodable_package_id(pkg_id, &state, resolve.version());
1073        if let Some(prev_pkg_id) = unique_pkg_ids.insert(encodable_pkd_id, pkg_id) {
1074            anyhow::bail!(
1075                "package collision in the lockfile: packages {} and {} are different, \
1076                 but only one can be written to lockfile unambiguously",
1077                prev_pkg_id,
1078                pkg_id
1079            )
1080        }
1081    }
1082    Ok(())
1083}