]> git.proxmox.com Git - cargo.git/blob - src/cargo/core/resolver/dep_cache.rs
Fix resolve error with cyclic dev-dependency features.
[cargo.git] / src / 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
12 use crate::core::resolver::context::Context;
13 use crate::core::resolver::errors::describe_path_in_context;
14 use crate::core::resolver::types::{ConflictReason, DepInfo, FeaturesSet};
15 use crate::core::resolver::{
16 ActivateError, ActivateResult, CliFeatures, RequestedFeatures, ResolveOpts, VersionOrdering,
17 VersionPreferences,
18 };
19 use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec, Registry, Summary};
20 use crate::util::errors::CargoResult;
21 use crate::util::interning::InternedString;
22
23 use anyhow::Context as _;
24 use log::debug;
25 use std::collections::{BTreeSet, HashMap, HashSet};
26 use std::rc::Rc;
27
28 pub struct RegistryQueryer<'a> {
29 pub registry: &'a mut (dyn Registry + 'a),
30 replacements: &'a [(PackageIdSpec, Dependency)],
31 version_prefs: &'a VersionPreferences,
32 /// If set the list of dependency candidates will be sorted by minimal
33 /// versions first. That allows `cargo update -Z minimal-versions` which will
34 /// specify minimum dependency versions to be used.
35 minimal_versions: bool,
36 /// a cache of `Candidate`s that fulfil a `Dependency`
37 registry_cache: HashMap<Dependency, Rc<Vec<Summary>>>,
38 /// a cache of `Dependency`s that are required for a `Summary`
39 summary_cache: HashMap<
40 (Option<PackageId>, Summary, ResolveOpts),
41 Rc<(HashSet<InternedString>, Rc<Vec<DepInfo>>)>,
42 >,
43 /// all the cases we ended up using a supplied replacement
44 used_replacements: HashMap<PackageId, Summary>,
45 }
46
47 impl<'a> RegistryQueryer<'a> {
48 pub fn new(
49 registry: &'a mut dyn Registry,
50 replacements: &'a [(PackageIdSpec, Dependency)],
51 version_prefs: &'a VersionPreferences,
52 minimal_versions: bool,
53 ) -> Self {
54 RegistryQueryer {
55 registry,
56 replacements,
57 version_prefs,
58 minimal_versions,
59 registry_cache: HashMap::new(),
60 summary_cache: HashMap::new(),
61 used_replacements: HashMap::new(),
62 }
63 }
64
65 pub fn used_replacement_for(&self, p: PackageId) -> Option<(PackageId, PackageId)> {
66 self.used_replacements.get(&p).map(|r| (p, r.package_id()))
67 }
68
69 pub fn replacement_summary(&self, p: PackageId) -> Option<&Summary> {
70 self.used_replacements.get(&p)
71 }
72
73 /// Queries the `registry` to return a list of candidates for `dep`.
74 ///
75 /// This method is the location where overrides are taken into account. If
76 /// any candidates are returned which match an override then the override is
77 /// applied by performing a second query for what the override should
78 /// return.
79 pub fn query(&mut self, dep: &Dependency) -> CargoResult<Rc<Vec<Summary>>> {
80 if let Some(out) = self.registry_cache.get(dep).cloned() {
81 return Ok(out);
82 }
83
84 let mut ret = Vec::new();
85 self.registry.query(
86 dep,
87 &mut |s| {
88 ret.push(s);
89 },
90 false,
91 )?;
92 for summary in ret.iter_mut() {
93 let mut potential_matches = self
94 .replacements
95 .iter()
96 .filter(|&&(ref spec, _)| spec.matches(summary.package_id()));
97
98 let &(ref spec, ref dep) = match potential_matches.next() {
99 None => continue,
100 Some(replacement) => replacement,
101 };
102 debug!(
103 "found an override for {} {}",
104 dep.package_name(),
105 dep.version_req()
106 );
107
108 let mut summaries = self.registry.query_vec(dep, false)?.into_iter();
109 let s = summaries.next().ok_or_else(|| {
110 anyhow::format_err!(
111 "no matching package for override `{}` found\n\
112 location searched: {}\n\
113 version required: {}",
114 spec,
115 dep.source_id(),
116 dep.version_req()
117 )
118 })?;
119 let summaries = summaries.collect::<Vec<_>>();
120 if !summaries.is_empty() {
121 let bullets = summaries
122 .iter()
123 .map(|s| format!(" * {}", s.package_id()))
124 .collect::<Vec<_>>();
125 anyhow::bail!(
126 "the replacement specification `{}` matched \
127 multiple packages:\n * {}\n{}",
128 spec,
129 s.package_id(),
130 bullets.join("\n")
131 );
132 }
133
134 // The dependency should be hard-coded to have the same name and an
135 // exact version requirement, so both of these assertions should
136 // never fail.
137 assert_eq!(s.version(), summary.version());
138 assert_eq!(s.name(), summary.name());
139
140 let replace = if s.source_id() == summary.source_id() {
141 debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s);
142 None
143 } else {
144 Some(s)
145 };
146 let matched_spec = spec.clone();
147
148 // Make sure no duplicates
149 if let Some(&(ref spec, _)) = potential_matches.next() {
150 anyhow::bail!(
151 "overlapping replacement specifications found:\n\n \
152 * {}\n * {}\n\nboth specifications match: {}",
153 matched_spec,
154 spec,
155 summary.package_id()
156 );
157 }
158
159 for dep in summary.dependencies() {
160 debug!("\t{} => {}", dep.package_name(), dep.version_req());
161 }
162 if let Some(r) = replace {
163 self.used_replacements.insert(summary.package_id(), r);
164 }
165 }
166
167 // When we attempt versions for a package we'll want to do so in a sorted fashion to pick
168 // the "best candidates" first. VersionPreferences implements this notion.
169 self.version_prefs.sort_summaries(
170 &mut ret,
171 if self.minimal_versions {
172 VersionOrdering::MinimumVersionsFirst
173 } else {
174 VersionOrdering::MaximumVersionsFirst
175 },
176 );
177
178 let out = Rc::new(ret);
179
180 self.registry_cache.insert(dep.clone(), out.clone());
181
182 Ok(out)
183 }
184
185 /// Find out what dependencies will be added by activating `candidate`,
186 /// with features described in `opts`. Then look up in the `registry`
187 /// the candidates that will fulfil each of these dependencies, as it is the
188 /// next obvious question.
189 pub fn build_deps(
190 &mut self,
191 cx: &Context,
192 parent: Option<PackageId>,
193 candidate: &Summary,
194 opts: &ResolveOpts,
195 ) -> ActivateResult<Rc<(HashSet<InternedString>, Rc<Vec<DepInfo>>)>> {
196 // if we have calculated a result before, then we can just return it,
197 // as it is a "pure" query of its arguments.
198 if let Some(out) = self
199 .summary_cache
200 .get(&(parent, candidate.clone(), opts.clone()))
201 .cloned()
202 {
203 return Ok(out);
204 }
205 // First, figure out our set of dependencies based on the requested set
206 // of features. This also calculates what features we're going to enable
207 // for our own dependencies.
208 let (used_features, deps) = resolve_features(parent, candidate, opts)?;
209
210 // Next, transform all dependencies into a list of possible candidates
211 // which can satisfy that dependency.
212 let mut deps = deps
213 .into_iter()
214 .map(|(dep, features)| {
215 let candidates = self.query(&dep).with_context(|| {
216 format!(
217 "failed to get `{}` as a dependency of {}",
218 dep.package_name(),
219 describe_path_in_context(cx, &candidate.package_id()),
220 )
221 })?;
222 Ok((dep, candidates, features))
223 })
224 .collect::<CargoResult<Vec<DepInfo>>>()?;
225
226 // Attempt to resolve dependencies with fewer candidates before trying
227 // dependencies with more candidates. This way if the dependency with
228 // only one candidate can't be resolved we don't have to do a bunch of
229 // work before we figure that out.
230 deps.sort_by_key(|&(_, ref a, _)| a.len());
231
232 let out = Rc::new((used_features, Rc::new(deps)));
233
234 // If we succeed we add the result to the cache so we can use it again next time.
235 // We don't cache the failure cases as they don't impl Clone.
236 self.summary_cache
237 .insert((parent, candidate.clone(), opts.clone()), out.clone());
238
239 Ok(out)
240 }
241 }
242
243 /// Returns the features we ended up using and
244 /// all dependencies and the features we want from each of them.
245 pub fn resolve_features<'b>(
246 parent: Option<PackageId>,
247 s: &'b Summary,
248 opts: &'b ResolveOpts,
249 ) -> ActivateResult<(HashSet<InternedString>, Vec<(Dependency, FeaturesSet)>)> {
250 // First, filter by dev-dependencies.
251 let deps = s.dependencies();
252 let deps = deps.iter().filter(|d| d.is_transitive() || opts.dev_deps);
253
254 let reqs = build_requirements(parent, s, opts)?;
255 let mut ret = Vec::new();
256 let default_dep = BTreeSet::new();
257 let mut valid_dep_names = HashSet::new();
258
259 // Next, collect all actually enabled dependencies and their features.
260 for dep in deps {
261 // Skip optional dependencies, but not those enabled through a
262 // feature
263 if dep.is_optional() && !reqs.deps.contains_key(&dep.name_in_toml()) {
264 continue;
265 }
266 valid_dep_names.insert(dep.name_in_toml());
267 // So we want this dependency. Move the features we want from
268 // `feature_deps` to `ret` and register ourselves as using this
269 // name.
270 let mut base = reqs
271 .deps
272 .get(&dep.name_in_toml())
273 .unwrap_or(&default_dep)
274 .clone();
275 base.extend(dep.features().iter());
276 ret.push((dep.clone(), Rc::new(base)));
277 }
278
279 // This is a special case for command-line `--features
280 // dep_name/feat_name` where `dep_name` does not exist. All other
281 // validation is done either in `build_requirements` or
282 // `build_feature_map`.
283 if parent.is_none() {
284 for dep_name in reqs.deps.keys() {
285 if !valid_dep_names.contains(dep_name) {
286 let e = RequirementError::MissingDependency(*dep_name);
287 return Err(e.into_activate_error(parent, s));
288 }
289 }
290 }
291
292 Ok((reqs.into_features(), ret))
293 }
294
295 /// Takes requested features for a single package from the input `ResolveOpts` and
296 /// recurses to find all requested features, dependencies and requested
297 /// dependency features in a `Requirements` object, returning it to the resolver.
298 fn build_requirements<'a, 'b: 'a>(
299 parent: Option<PackageId>,
300 s: &'a Summary,
301 opts: &'b ResolveOpts,
302 ) -> ActivateResult<Requirements<'a>> {
303 let mut reqs = Requirements::new(s);
304
305 let handle_default = |uses_default_features, reqs: &mut Requirements<'_>| {
306 if uses_default_features && s.features().contains_key("default") {
307 if let Err(e) = reqs.require_feature(InternedString::new("default")) {
308 return Err(e.into_activate_error(parent, s));
309 }
310 }
311 Ok(())
312 };
313
314 match &opts.features {
315 RequestedFeatures::CliFeatures(CliFeatures {
316 features,
317 all_features,
318 uses_default_features,
319 }) => {
320 if *all_features {
321 for key in s.features().keys() {
322 if let Err(e) = reqs.require_feature(*key) {
323 return Err(e.into_activate_error(parent, s));
324 }
325 }
326 } else {
327 for fv in features.iter() {
328 if let Err(e) = reqs.require_value(fv) {
329 return Err(e.into_activate_error(parent, s));
330 }
331 }
332 handle_default(*uses_default_features, &mut reqs)?;
333 }
334 }
335 RequestedFeatures::DepFeatures {
336 features,
337 uses_default_features,
338 } => {
339 for feature in features.iter() {
340 if let Err(e) = reqs.require_feature(*feature) {
341 return Err(e.into_activate_error(parent, s));
342 }
343 }
344 handle_default(*uses_default_features, &mut reqs)?;
345 }
346 }
347
348 Ok(reqs)
349 }
350
351 /// Set of feature and dependency requirements for a package.
352 #[derive(Debug)]
353 struct Requirements<'a> {
354 summary: &'a Summary,
355 /// The deps map is a mapping of dependency name to list of features enabled.
356 ///
357 /// The resolver will activate all of these dependencies, with the given
358 /// features enabled.
359 deps: HashMap<InternedString, BTreeSet<InternedString>>,
360 /// The set of features enabled on this package which is later used when
361 /// compiling to instruct the code what features were enabled.
362 features: HashSet<InternedString>,
363 }
364
365 /// An error for a requirement.
366 ///
367 /// This will later be converted to an `ActivateError` depending on whether or
368 /// not this is a dependency or a root package.
369 enum RequirementError {
370 /// The package does not have the requested feature.
371 MissingFeature(InternedString),
372 /// The package does not have the requested dependency.
373 MissingDependency(InternedString),
374 /// A feature has a direct cycle to itself.
375 ///
376 /// Note that cycles through multiple features are allowed (but perhaps
377 /// they shouldn't be?).
378 Cycle(InternedString),
379 }
380
381 impl Requirements<'_> {
382 fn new(summary: &Summary) -> Requirements<'_> {
383 Requirements {
384 summary,
385 deps: HashMap::new(),
386 features: HashSet::new(),
387 }
388 }
389
390 fn into_features(self) -> HashSet<InternedString> {
391 self.features
392 }
393
394 fn require_dep_feature(
395 &mut self,
396 package: InternedString,
397 feat: InternedString,
398 weak: bool,
399 ) -> Result<(), RequirementError> {
400 // If `package` is indeed an optional dependency then we activate the
401 // feature named `package`, but otherwise if `package` is a required
402 // dependency then there's no feature associated with it.
403 if !weak
404 && self
405 .summary
406 .dependencies()
407 .iter()
408 .any(|dep| dep.name_in_toml() == package && dep.is_optional())
409 {
410 self.require_feature(package)?;
411 }
412 self.deps.entry(package).or_default().insert(feat);
413 Ok(())
414 }
415
416 fn require_dependency(&mut self, pkg: InternedString) {
417 self.deps.entry(pkg).or_default();
418 }
419
420 fn require_feature(&mut self, feat: InternedString) -> Result<(), RequirementError> {
421 if !self.features.insert(feat) {
422 // Already seen this feature.
423 return Ok(());
424 }
425
426 let fvs = match self.summary.features().get(&feat) {
427 Some(fvs) => fvs,
428 None => return Err(RequirementError::MissingFeature(feat)),
429 };
430
431 for fv in fvs {
432 if let FeatureValue::Feature(dep_feat) = fv {
433 if *dep_feat == feat {
434 return Err(RequirementError::Cycle(feat));
435 }
436 }
437 self.require_value(fv)?;
438 }
439 Ok(())
440 }
441
442 fn require_value(&mut self, fv: &FeatureValue) -> Result<(), RequirementError> {
443 match fv {
444 FeatureValue::Feature(feat) => self.require_feature(*feat)?,
445 FeatureValue::Dep { dep_name } => self.require_dependency(*dep_name),
446 FeatureValue::DepFeature {
447 dep_name,
448 dep_feature,
449 // Weak features are always activated in the dependency
450 // resolver. They will be narrowed inside the new feature
451 // resolver.
452 weak,
453 } => self.require_dep_feature(*dep_name, *dep_feature, *weak)?,
454 };
455 Ok(())
456 }
457 }
458
459 impl RequirementError {
460 fn into_activate_error(self, parent: Option<PackageId>, summary: &Summary) -> ActivateError {
461 match self {
462 RequirementError::MissingFeature(feat) => {
463 let deps: Vec<_> = summary
464 .dependencies()
465 .iter()
466 .filter(|dep| dep.name_in_toml() == feat)
467 .collect();
468 if deps.is_empty() {
469 return match parent {
470 None => ActivateError::Fatal(anyhow::format_err!(
471 "Package `{}` does not have the feature `{}`",
472 summary.package_id(),
473 feat
474 )),
475 Some(p) => ActivateError::Conflict(
476 p,
477 ConflictReason::MissingFeatures(feat.to_string()),
478 ),
479 };
480 }
481 if deps.iter().any(|dep| dep.is_optional()) {
482 match parent {
483 None => ActivateError::Fatal(anyhow::format_err!(
484 "Package `{}` does not have feature `{}`. It has an optional dependency \
485 with that name, but that dependency uses the \"dep:\" \
486 syntax in the features table, so it does not have an implicit feature with that name.",
487 summary.package_id(),
488 feat
489 )),
490 Some(p) => ActivateError::Conflict(
491 p,
492 ConflictReason::NonImplicitDependencyAsFeature(feat),
493 ),
494 }
495 } else {
496 match parent {
497 None => ActivateError::Fatal(anyhow::format_err!(
498 "Package `{}` does not have feature `{}`. It has a required dependency \
499 with that name, but only optional dependencies can be used as features.",
500 summary.package_id(),
501 feat
502 )),
503 Some(p) => ActivateError::Conflict(
504 p,
505 ConflictReason::RequiredDependencyAsFeature(feat),
506 ),
507 }
508 }
509 }
510 RequirementError::MissingDependency(dep_name) => {
511 match parent {
512 None => ActivateError::Fatal(anyhow::format_err!(
513 "package `{}` does not have a dependency named `{}`",
514 summary.package_id(),
515 dep_name
516 )),
517 // This code path currently isn't used, since `foo/bar`
518 // and `dep:` syntax is not allowed in a dependency.
519 Some(p) => ActivateError::Conflict(
520 p,
521 ConflictReason::MissingFeatures(dep_name.to_string()),
522 ),
523 }
524 }
525 RequirementError::Cycle(feat) => ActivateError::Fatal(anyhow::format_err!(
526 "cyclic feature dependency: feature `{}` depends on itself",
527 feat
528 )),
529 }
530 }
531 }