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