Skip to main content

cargo/core/resolver/
dep_cache.rs

1//! There are 2 sources of facts for the resolver:
2//!
3//! - The `Registry` tells us for a `Dependency` what versions are available to fulfil it.
4//! - The `Summary` tells us for a version (and features) what dependencies need to be fulfilled for it to be activated.
5//!
6//! These constitute immutable facts, the soled ground truth that all other inference depends on.
7//! Theoretically this could all be enumerated ahead of time, but we want to be lazy and only
8//! look up things we need to. The compromise is to cache the results as they are computed.
9//!
10//! This module impl that cache in all the gory details
11
12use crate::core::resolver::context::ResolverContext;
13use crate::core::resolver::errors::describe_path_in_context;
14use crate::core::resolver::types::{ConflictReason, DepInfo, FeaturesSet};
15use crate::core::resolver::{
16    ActivateError, ActivateResult, CliFeatures, RequestedFeatures, ResolveOpts, VersionOrdering,
17    VersionPreferences,
18};
19use crate::core::{
20    Dependency, FeatureValue, PackageId, PackageIdSpec, PackageIdSpecQuery, Registry, Summary,
21};
22use crate::sources::source::QueryKind;
23use crate::util::LocalPollAdapter;
24use crate::util::closest_msg;
25use crate::util::errors::CargoResult;
26use crate::util::interning::{INTERNED_DEFAULT, InternedString};
27
28use anyhow::Context as _;
29use std::cell::RefCell;
30use std::collections::{BTreeSet, HashMap, HashSet};
31use std::fmt::Write;
32use std::rc::Rc;
33use std::task::Poll;
34use tracing::debug;
35
36pub struct RegistryQueryerAsync<'a, T: Registry> {
37    pub registry: &'a T,
38    replacements: &'a [(PackageIdSpec, Dependency)],
39    version_prefs: &'a VersionPreferences,
40    /// all the cases we ended up using a supplied replacement
41    used_replacements: RefCell<HashMap<PackageId, Summary>>,
42}
43
44impl<'a, T: Registry> RegistryQueryerAsync<'a, T> {
45    pub fn new(
46        registry: &'a T,
47        replacements: &'a [(PackageIdSpec, Dependency)],
48        version_prefs: &'a VersionPreferences,
49    ) -> Self {
50        RegistryQueryerAsync {
51            registry,
52            replacements,
53            version_prefs,
54            used_replacements: RefCell::new(HashMap::new()),
55        }
56    }
57
58    /// Queries the `registry` to return a list of candidates for `dep`.
59    ///
60    /// This method is the location where overrides are taken into account. If
61    /// any candidates are returned which match an override then the override is
62    /// applied by performing a second query for what the override should
63    /// return.
64    async fn query(
65        &self,
66        key: &(Dependency, Option<VersionOrdering>),
67    ) -> CargoResult<Rc<Vec<Summary>>> {
68        let (dep, first_version) = key;
69        let mut summaries = Vec::new();
70        self.registry
71            .query(dep, QueryKind::Exact, &mut |s| {
72                summaries.push(s.into_summary());
73            })
74            .await?;
75
76        for summary in summaries.iter() {
77            let mut potential_matches = self
78                .replacements
79                .iter()
80                .filter(|(spec, _)| spec.matches(summary.package_id()));
81
82            let Some((spec, dep)) = potential_matches.next() else {
83                continue;
84            };
85            debug!(
86                "found an override for {} {}",
87                dep.package_name(),
88                dep.version_req()
89            );
90
91            let mut summaries = self
92                .registry
93                .query_vec(dep, QueryKind::Exact)
94                .await?
95                .into_iter();
96            let s = summaries
97                .next()
98                .ok_or_else(|| {
99                    anyhow::format_err!(
100                        "no matching package for override `{}` found\n\
101                     location searched: {}\n\
102                     version required: {}",
103                        spec,
104                        dep.source_id(),
105                        dep.version_req()
106                    )
107                })?
108                .into_summary();
109            let summaries = summaries.collect::<Vec<_>>();
110            if !summaries.is_empty() {
111                let bullets = summaries
112                    .iter()
113                    .map(|s| format!("  * {}", s.package_id()))
114                    .collect::<Vec<_>>();
115                return Err(anyhow::anyhow!(
116                    "the replacement specification `{}` matched \
117                     multiple packages:\n  * {}\n{}",
118                    spec,
119                    s.package_id(),
120                    bullets.join("\n")
121                ));
122            }
123
124            assert_eq!(
125                s.name(),
126                summary.name(),
127                "dependency should be hard coded to have the same name"
128            );
129            if s.version() != summary.version() {
130                return Err(anyhow::anyhow!(
131                    "replacement specification `{}` matched {} and tried to override it with {}\n\
132                     avoid matching unrelated packages by being more specific",
133                    spec,
134                    summary.version(),
135                    s.version(),
136                ));
137            }
138
139            let replace = if s.source_id() == summary.source_id() {
140                debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s);
141                None
142            } else {
143                Some(s)
144            };
145            let matched_spec = spec.clone();
146
147            // Make sure no duplicates
148            if let Some((spec, _)) = potential_matches.next() {
149                return Err(anyhow::anyhow!(
150                    "overlapping replacement specifications found:\n\n  \
151                     * {}\n  * {}\n\nboth specifications match: {}",
152                    matched_spec,
153                    spec,
154                    summary.package_id()
155                ));
156            }
157
158            for dep in summary.dependencies() {
159                debug!("\t{} => {}", dep.package_name(), dep.version_req());
160            }
161            if let Some(r) = replace {
162                self.used_replacements
163                    .borrow_mut()
164                    .insert(summary.package_id(), r);
165            }
166        }
167
168        self.version_prefs
169            .sort_summaries(&mut summaries, *first_version);
170        Ok(Rc::new(summaries))
171    }
172}
173
174/// Wrapper around RegistryQueryerAsync that provides
175/// caching and a Poll based interface using `LocalPollAdapter`.
176pub struct RegistryQueryer<'a, T: Registry> {
177    inner: Rc<RegistryQueryerAsync<'a, T>>,
178    poller: LocalPollAdapter<
179        'a,
180        Rc<RegistryQueryerAsync<'a, T>>,
181        (Dependency, Option<VersionOrdering>),
182        CargoResult<Rc<Vec<Summary>>>,
183    >,
184
185    /// a cache of `Dependency`s that are required for a `Summary`
186    ///
187    /// HACK: `first_version` is not kept in the cache key is it is 1:1 with
188    /// `parent.is_none()` (the first element of the cache key) as it doesn't change through
189    /// execution.
190    summary_cache: HashMap<
191        (Option<PackageId>, Summary, ResolveOpts),
192        (Rc<(HashSet<InternedString>, Rc<Vec<DepInfo>>)>, bool),
193    >,
194}
195
196impl<'a, T: Registry> RegistryQueryer<'a, T> {
197    pub fn new(
198        registry: &'a T,
199        replacements: &'a [(PackageIdSpec, Dependency)],
200        version_prefs: &'a VersionPreferences,
201    ) -> Self {
202        let inner = Rc::new(RegistryQueryerAsync::new(
203            registry,
204            replacements,
205            version_prefs,
206        ));
207        Self {
208            inner: inner.clone(),
209            poller: LocalPollAdapter::new(inner),
210            summary_cache: HashMap::new(),
211        }
212    }
213
214    pub fn registry(&self) -> &T {
215        self.inner.registry
216    }
217
218    pub fn query(
219        &mut self,
220        dep: &Dependency,
221        first_version: Option<VersionOrdering>,
222    ) -> Poll<CargoResult<Rc<Vec<Summary>>>> {
223        self.poller
224            .poll(RegistryQueryerAsync::query, (dep.clone(), first_version))
225    }
226
227    pub fn wait(&mut self) -> CargoResult<bool> {
228        let pending = self.poller.pending_count();
229        // Have all outstanding registry requests been completed?
230        let mut all_ready = self.poller.wait();
231        debug!(target: "cargo::core::resolver::restarting", pending);
232
233        // Remove cached summaries that we produced with incomplete information.
234        self.summary_cache.retain(|_, (_, r)| {
235            if !*r {
236                all_ready = false;
237            }
238            *r
239        });
240
241        Ok(all_ready)
242    }
243
244    pub fn used_replacement_for(&self, p: PackageId) -> Option<(PackageId, PackageId)> {
245        self.inner
246            .used_replacements
247            .borrow()
248            .get(&p)
249            .map(|r| (p, r.package_id()))
250    }
251
252    pub fn replacement_summary(&self, p: PackageId) -> Option<Summary> {
253        self.inner.used_replacements.borrow().get(&p).cloned()
254    }
255
256    /// Find out what dependencies will be added by activating `candidate`,
257    /// with features described in `opts`. Then look up in the `registry`
258    /// the candidates that will fulfil each of these dependencies, as it is the
259    /// next obvious question.
260    pub fn build_deps(
261        &mut self,
262        cx: &ResolverContext,
263        parent: Option<PackageId>,
264        candidate: &Summary,
265        opts: &ResolveOpts,
266        first_version: Option<VersionOrdering>,
267    ) -> ActivateResult<Rc<(HashSet<InternedString>, Rc<Vec<DepInfo>>)>> {
268        // if we have calculated a result before, then we can just return it,
269        // as it is a "pure" query of its arguments.
270        if let Some(out) = self
271            .summary_cache
272            .get(&(parent, candidate.clone(), opts.clone()))
273        {
274            return Ok(out.0.clone());
275        }
276        // First, figure out our set of dependencies based on the requested set
277        // of features. This also calculates what features we're going to enable
278        // for our own dependencies.
279        let (used_features, deps) = resolve_features(parent, candidate, opts)?;
280
281        // Next, transform all dependencies into a list of possible candidates
282        // which can satisfy that dependency.
283        let mut all_ready = true;
284        let mut deps = deps
285            .into_iter()
286            .filter_map(|(dep, features)| match self.query(&dep, first_version) {
287                Poll::Ready(Ok(candidates)) => Some(Ok((dep, candidates, features))),
288                Poll::Pending => {
289                    all_ready = false;
290                    // we can ignore Pending deps, resolve will be repeatedly called
291                    // until there are none to ignore
292                    None
293                }
294                Poll::Ready(Err(e)) => Some(Err(e).with_context(|| {
295                    format!(
296                        "failed to get `{}` as a dependency of {}",
297                        dep.package_name(),
298                        describe_path_in_context(cx, &candidate.package_id()),
299                    )
300                })),
301            })
302            .collect::<CargoResult<Vec<DepInfo>>>()?;
303
304        // Attempt to resolve dependencies with fewer candidates before trying
305        // dependencies with more candidates. This way if the dependency with
306        // only one candidate can't be resolved we don't have to do a bunch of
307        // work before we figure that out.
308        deps.sort_by_key(|(_, a, _)| a.len());
309
310        let out = Rc::new((used_features, Rc::new(deps)));
311
312        // If we succeed we add the result to the cache so we can use it again next time.
313        // We don't cache the failure cases as they don't impl Clone.
314        self.summary_cache.insert(
315            (parent, candidate.clone(), opts.clone()),
316            (out.clone(), all_ready),
317        );
318
319        Ok(out)
320    }
321}
322
323/// Returns the features we ended up using and
324/// all dependencies and the features we want from each of them.
325pub fn resolve_features<'b>(
326    parent: Option<PackageId>,
327    s: &'b Summary,
328    opts: &'b ResolveOpts,
329) -> ActivateResult<(HashSet<InternedString>, Vec<(Dependency, FeaturesSet)>)> {
330    // First, filter by dev-dependencies.
331    let deps = s.dependencies();
332    let deps = deps.iter().filter(|d| d.is_transitive() || opts.dev_deps);
333
334    let reqs = build_requirements(parent, s, opts)?;
335    let mut ret = Vec::new();
336    let default_dep = BTreeSet::new();
337    let mut valid_dep_names = HashSet::new();
338
339    // Next, collect all actually enabled dependencies and their features.
340    for dep in deps {
341        // Skip optional dependencies, but not those enabled through a
342        // feature
343        if dep.is_optional() && !reqs.deps.contains_key(&dep.name_in_toml()) {
344            continue;
345        }
346        valid_dep_names.insert(dep.name_in_toml());
347        // So we want this dependency. Move the features we want from
348        // `feature_deps` to `ret` and register ourselves as using this
349        // name.
350        let mut base = reqs
351            .deps
352            .get(&dep.name_in_toml())
353            .unwrap_or(&default_dep)
354            .clone();
355        base.extend(dep.features().iter());
356        ret.push((dep.clone(), Rc::new(base)));
357    }
358
359    // This is a special case for command-line `--features
360    // dep_name/feat_name` where `dep_name` does not exist. All other
361    // validation is done either in `build_requirements` or
362    // `build_feature_map`.
363    if parent.is_none() {
364        for dep_name in reqs.deps.keys() {
365            if !valid_dep_names.contains(dep_name) {
366                let e = RequirementError::MissingDependency(*dep_name);
367                return Err(e.into_activate_error(parent, s));
368            }
369        }
370    }
371
372    Ok((reqs.into_features(), ret))
373}
374
375/// Takes requested features for a single package from the input `ResolveOpts` and
376/// recurses to find all requested features, dependencies and requested
377/// dependency features in a `Requirements` object, returning it to the resolver.
378fn build_requirements<'a, 'b: 'a>(
379    parent: Option<PackageId>,
380    s: &'a Summary,
381    opts: &'b ResolveOpts,
382) -> ActivateResult<Requirements<'a>> {
383    let mut reqs = Requirements::new(s);
384
385    let handle_default = |uses_default_features, reqs: &mut Requirements<'_>| {
386        if uses_default_features && s.features().contains_key("default") {
387            if let Err(e) = reqs.require_feature(INTERNED_DEFAULT) {
388                return Err(e.into_activate_error(parent, s));
389            }
390        }
391        Ok(())
392    };
393
394    match &opts.features {
395        RequestedFeatures::CliFeatures(CliFeatures {
396            features,
397            all_features,
398            uses_default_features,
399        }) => {
400            if *all_features {
401                for key in s.features().keys() {
402                    if let Err(e) = reqs.require_feature(*key) {
403                        return Err(e.into_activate_error(parent, s));
404                    }
405                }
406            }
407
408            for fv in features.iter() {
409                if let Err(e) = reqs.require_value(fv) {
410                    return Err(e.into_activate_error(parent, s));
411                }
412            }
413            handle_default(*uses_default_features, &mut reqs)?;
414        }
415        RequestedFeatures::DepFeatures {
416            features,
417            uses_default_features,
418        } => {
419            for feature in features.iter() {
420                if let Err(e) = reqs.require_feature(*feature) {
421                    return Err(e.into_activate_error(parent, s));
422                }
423            }
424            handle_default(*uses_default_features, &mut reqs)?;
425        }
426    }
427
428    Ok(reqs)
429}
430
431/// Set of feature and dependency requirements for a package.
432#[derive(Debug)]
433struct Requirements<'a> {
434    summary: &'a Summary,
435    /// The deps map is a mapping of dependency name to list of features enabled.
436    ///
437    /// The resolver will activate all of these dependencies, with the given
438    /// features enabled.
439    deps: HashMap<InternedString, BTreeSet<InternedString>>,
440    /// The set of features enabled on this package which is later used when
441    /// compiling to instruct the code what features were enabled.
442    features: HashSet<InternedString>,
443}
444
445/// An error for a requirement.
446///
447/// This will later be converted to an `ActivateError` depending on whether or
448/// not this is a dependency or a root package.
449enum RequirementError {
450    /// The package does not have the requested feature.
451    MissingFeature(InternedString),
452    /// The package does not have the requested dependency.
453    MissingDependency(InternedString),
454    /// A feature has a direct cycle to itself.
455    ///
456    /// Note that cycles through multiple features are allowed (but perhaps
457    /// they shouldn't be?).
458    Cycle(InternedString),
459}
460
461impl Requirements<'_> {
462    fn new(summary: &Summary) -> Requirements<'_> {
463        Requirements {
464            summary,
465            deps: HashMap::new(),
466            features: HashSet::new(),
467        }
468    }
469
470    fn into_features(self) -> HashSet<InternedString> {
471        self.features
472    }
473
474    fn require_dep_feature(
475        &mut self,
476        package: InternedString,
477        feat: InternedString,
478        weak: bool,
479    ) -> Result<(), RequirementError> {
480        // If `package` is indeed an optional dependency then we activate the
481        // feature named `package`, but otherwise if `package` is a required
482        // dependency then there's no feature associated with it.
483        if !weak
484            && self
485                .summary
486                .dependencies()
487                .iter()
488                .any(|dep| dep.name_in_toml() == package && dep.is_optional())
489        {
490            // This optional dependency may not have an implicit feature of
491            // the same name if the `dep:` syntax is used to avoid creating
492            // that implicit feature.
493            if self.summary.features().contains_key(&package) {
494                self.require_feature(package)?;
495            }
496        }
497        self.deps.entry(package).or_default().insert(feat);
498        Ok(())
499    }
500
501    fn require_dependency(&mut self, pkg: InternedString) {
502        self.deps.entry(pkg).or_default();
503    }
504
505    fn require_feature(&mut self, feat: InternedString) -> Result<(), RequirementError> {
506        if !self.features.insert(feat) {
507            // Already seen this feature.
508            return Ok(());
509        }
510
511        let Some(fvs) = self.summary.features().get(&feat) else {
512            return Err(RequirementError::MissingFeature(feat));
513        };
514
515        for fv in fvs {
516            if let FeatureValue::Feature(dep_feat) = fv {
517                if *dep_feat == feat {
518                    return Err(RequirementError::Cycle(feat));
519                }
520            }
521            self.require_value(fv)?;
522        }
523        Ok(())
524    }
525
526    fn require_value(&mut self, fv: &FeatureValue) -> Result<(), RequirementError> {
527        match fv {
528            FeatureValue::Feature(feat) => self.require_feature(*feat)?,
529            FeatureValue::Dep { dep_name } => self.require_dependency(*dep_name),
530            FeatureValue::DepFeature {
531                dep_name,
532                dep_feature,
533                // Weak features are always activated in the dependency
534                // resolver. They will be narrowed inside the new feature
535                // resolver.
536                weak,
537            } => self.require_dep_feature(*dep_name, *dep_feature, *weak)?,
538        };
539        Ok(())
540    }
541}
542
543impl RequirementError {
544    fn into_activate_error(self, parent: Option<PackageId>, summary: &Summary) -> ActivateError {
545        match self {
546            RequirementError::MissingFeature(feat) => {
547                let deps: Vec<_> = summary
548                    .dependencies()
549                    .iter()
550                    .filter(|dep| dep.name_in_toml() == feat)
551                    .collect();
552                if deps.is_empty() {
553                    return match parent {
554                        None => {
555                            let closest = closest_msg(
556                                &feat.as_str(),
557                                summary.features().keys(),
558                                |key| &key,
559                                "feature",
560                            );
561                            ActivateError::Fatal(anyhow::format_err!(
562                                "package `{}` does not have the feature `{}`{}",
563                                summary.package_id(),
564                                feat,
565                                closest
566                            ))
567                        }
568                        Some(p) => ActivateError::Conflict(p, ConflictReason::MissingFeature(feat)),
569                    };
570                }
571                if deps.iter().any(|dep| dep.is_optional()) {
572                    match parent {
573                        None => {
574                            let mut features =
575                                features_enabling_dependency_sorted(summary, feat).peekable();
576                            let mut suggestion = String::new();
577                            if features.peek().is_some() {
578                                suggestion = format!(
579                                    "\nDependency `{}` would be enabled by these features:",
580                                    feat
581                                );
582                                for feature in (&mut features).take(3) {
583                                    let _ = write!(&mut suggestion, "\n\t- `{}`", feature);
584                                }
585                                if features.peek().is_some() {
586                                    suggestion.push_str("\n\t  ...");
587                                }
588                            }
589                            ActivateError::Fatal(anyhow::format_err!(
590                                "\
591package `{}` does not have feature `{}`
592
593help: an optional dependency \
594with that name exists, but the `features` table includes it with the \"dep:\" \
595syntax so it does not have an implicit feature with that name{}",
596                                summary.package_id(),
597                                feat,
598                                suggestion
599                            ))
600                        }
601                        Some(p) => ActivateError::Conflict(
602                            p,
603                            ConflictReason::NonImplicitDependencyAsFeature(feat),
604                        ),
605                    }
606                } else {
607                    match parent {
608                        None => ActivateError::Fatal(anyhow::format_err!(
609                            "package `{}` does not have feature `{}`
610
611help: a dependency with that name exists but it is required dependency and only optional dependencies can be used as features.",
612                            summary.package_id(),
613                            feat,
614                        )),
615                        Some(p) => ActivateError::Conflict(
616                            p,
617                            ConflictReason::RequiredDependencyAsFeature(feat),
618                        ),
619                    }
620                }
621            }
622            RequirementError::MissingDependency(dep_name) => {
623                match parent {
624                    None => ActivateError::Fatal(anyhow::format_err!(
625                        "package `{}` does not have a dependency named `{}`",
626                        summary.package_id(),
627                        dep_name
628                    )),
629                    // This code path currently isn't used, since `foo/bar`
630                    // and `dep:` syntax is not allowed in a dependency.
631                    Some(p) => ActivateError::Conflict(p, ConflictReason::MissingFeature(dep_name)),
632                }
633            }
634            RequirementError::Cycle(feat) => ActivateError::Fatal(anyhow::format_err!(
635                "cyclic feature dependency: feature `{}` depends on itself",
636                feat
637            )),
638        }
639    }
640}
641
642/// Collect any features which enable the optional dependency "target_dep".
643///
644/// The returned value will be sorted.
645fn features_enabling_dependency_sorted(
646    summary: &Summary,
647    target_dep: InternedString,
648) -> impl Iterator<Item = InternedString> + '_ {
649    let iter = summary
650        .features()
651        .iter()
652        .filter(move |(_, values)| {
653            for value in *values {
654                match value {
655                    FeatureValue::Dep { dep_name }
656                    | FeatureValue::DepFeature {
657                        dep_name,
658                        weak: false,
659                        ..
660                    } if dep_name == &target_dep => return true,
661                    _ => (),
662                }
663            }
664            false
665        })
666        .map(|(name, _)| *name);
667    // iter is already sorted because it was constructed from a BTreeMap.
668    iter
669}