Skip to content

Commit cb0f763

Browse files
committed
Auto merge of #6653 - Eh2406:min-pub-dep, r=alexcrichton
part of the infrastructure for public & private dependencies in the resolver This is part of my work on public & private dependencies in the resolver from #6129. As discussed there the proptest fuzzers are happy to find exponential blow up with all the back jumping strategies I have tried. So this PR does not have a back jumping strategie nor does it have the proptest fuzzers generating public dependencies. These will both need to change for the feature to stabilize. In the meantime it gives the correct results on the cases it can handle. With rust-lang/rust#57586 landed there is a lot of work to do on Cargos front end. Adding a UI for this, passing the relevant things to rustc, passing it to crates.io, passing it to cargo-metadata. This is good enough to allow that work to proceed.
2 parents 0d2aac7 + 12e474b commit cb0f763

File tree

11 files changed

+411
-86
lines changed

11 files changed

+411
-86
lines changed

src/cargo/core/dependency.rs

+12
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct Inner {
4040
explicit_name_in_toml: Option<InternedString>,
4141

4242
optional: bool,
43+
public: bool,
4344
default_features: bool,
4445
features: Vec<InternedString>,
4546

@@ -217,6 +218,7 @@ impl Dependency {
217218
kind: Kind::Normal,
218219
only_match_name: true,
219220
optional: false,
221+
public: false,
220222
features: Vec::new(),
221223
default_features: true,
222224
specified_req: false,
@@ -293,6 +295,16 @@ impl Dependency {
293295
self.inner.kind
294296
}
295297

298+
pub fn is_public(&self) -> bool {
299+
self.inner.public
300+
}
301+
302+
/// Sets whether the dependency is public.
303+
pub fn set_public(&mut self, public: bool) -> &mut Dependency {
304+
Rc::make_mut(&mut self.inner).public = public;
305+
self
306+
}
307+
296308
pub fn specified_req(&self) -> bool {
297309
self.inner.specified_req
298310
}

src/cargo/core/resolver/conflict_cache.rs

+13-16
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ use std::collections::{BTreeMap, HashMap, HashSet};
22

33
use log::trace;
44

5-
use super::types::ConflictReason;
5+
use super::types::{ConflictMap, ConflictReason};
66
use crate::core::resolver::Context;
77
use crate::core::{Dependency, PackageId};
88

99
/// This is a trie for storing a large number of sets designed to
1010
/// efficiently see if any of the stored sets are a subset of a search set.
1111
enum ConflictStoreTrie {
1212
/// One of the stored sets.
13-
Leaf(BTreeMap<PackageId, ConflictReason>),
13+
Leaf(ConflictMap),
1414
/// A map from an element to a subtrie where
1515
/// all the sets in the subtrie contains that element.
1616
Node(BTreeMap<PackageId, ConflictStoreTrie>),
@@ -23,7 +23,7 @@ impl ConflictStoreTrie {
2323
&self,
2424
cx: &Context,
2525
must_contain: Option<PackageId>,
26-
) -> Option<&BTreeMap<PackageId, ConflictReason>> {
26+
) -> Option<&ConflictMap> {
2727
match self {
2828
ConflictStoreTrie::Leaf(c) => {
2929
if must_contain.is_none() {
@@ -57,18 +57,14 @@ impl ConflictStoreTrie {
5757
}
5858
}
5959

60-
fn insert(
61-
&mut self,
62-
mut iter: impl Iterator<Item = PackageId>,
63-
con: BTreeMap<PackageId, ConflictReason>,
64-
) {
60+
fn insert(&mut self, mut iter: impl Iterator<Item = PackageId>, con: ConflictMap) {
6561
if let Some(pid) = iter.next() {
6662
if let ConflictStoreTrie::Node(p) = self {
6763
p.entry(pid)
6864
.or_insert_with(|| ConflictStoreTrie::Node(BTreeMap::new()))
6965
.insert(iter, con);
7066
}
71-
// Else, we already have a subset of this in the `ConflictStore`.
67+
// Else, we already have a subset of this in the `ConflictStore`.
7268
} else {
7369
// We are at the end of the set we are adding, there are three cases for what to do
7470
// next:
@@ -147,7 +143,7 @@ impl ConflictCache {
147143
cx: &Context,
148144
dep: &Dependency,
149145
must_contain: Option<PackageId>,
150-
) -> Option<&BTreeMap<PackageId, ConflictReason>> {
146+
) -> Option<&ConflictMap> {
151147
let out = self
152148
.con_from_dep
153149
.get(dep)?
@@ -161,18 +157,19 @@ impl ConflictCache {
161157
}
162158
out
163159
}
164-
pub fn conflicting(
165-
&self,
166-
cx: &Context,
167-
dep: &Dependency,
168-
) -> Option<&BTreeMap<PackageId, ConflictReason>> {
160+
pub fn conflicting(&self, cx: &Context, dep: &Dependency) -> Option<&ConflictMap> {
169161
self.find_conflicting(cx, dep, None)
170162
}
171163

172164
/// Adds to the cache a conflict of the form:
173165
/// `dep` is known to be unresolvable if
174166
/// all the `PackageId` entries are activated.
175-
pub fn insert(&mut self, dep: &Dependency, con: &BTreeMap<PackageId, ConflictReason>) {
167+
pub fn insert(&mut self, dep: &Dependency, con: &ConflictMap) {
168+
if con.values().any(|c| *c == ConflictReason::PublicDependency) {
169+
// TODO: needs more info for back jumping
170+
// for now refuse to cache it.
171+
return;
172+
}
176173
self.con_from_dep
177174
.entry(dep.clone())
178175
.or_insert_with(|| ConflictStoreTrie::Node(BTreeMap::new()))

src/cargo/core/resolver/context.rs

+25-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::{BTreeMap, HashMap, HashSet};
1+
use std::collections::{HashMap, HashSet};
22
use std::rc::Rc;
33

44
// "ensure" seems to require "bail" be in scope (macro hygiene issue?).
@@ -12,7 +12,9 @@ use crate::util::CargoResult;
1212
use crate::util::Graph;
1313

1414
use super::errors::ActivateResult;
15-
use super::types::{ConflictReason, DepInfo, GraphNode, Method, RcList, RegistryQueryer};
15+
use super::types::{
16+
ConflictMap, ConflictReason, DepInfo, GraphNode, Method, RcList, RegistryQueryer,
17+
};
1618

1719
pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
1820
pub use super::encode::{Metadata, WorkspaceResolve};
@@ -25,8 +27,20 @@ pub use super::resolve::Resolve;
2527
#[derive(Clone)]
2628
pub struct Context {
2729
pub activations: Activations,
30+
/// list the features that are activated for each package
2831
pub resolve_features: im_rc::HashMap<PackageId, Rc<HashSet<InternedString>>>,
32+
/// get the package that will be linking to a native library by its links attribute
2933
pub links: im_rc::HashMap<InternedString, PackageId>,
34+
/// for each package the list of names it can see,
35+
/// then for each name the exact version that name represents and weather the name is public.
36+
pub public_dependency:
37+
Option<im_rc::HashMap<PackageId, im_rc::HashMap<InternedString, (PackageId, bool)>>>,
38+
39+
// This is somewhat redundant with the `resolve_graph` that stores the same data,
40+
// but for querying in the opposite order.
41+
/// a way to look up for a package in activations what packages required it
42+
/// and all of the exact deps that it fulfilled.
43+
pub parents: Graph<PackageId, Rc<Vec<Dependency>>>,
3044

3145
// These are two cheaply-cloneable lists (O(1) clone) which are effectively
3246
// hash maps but are built up as "construction lists". We'll iterate these
@@ -38,14 +52,21 @@ pub struct Context {
3852
pub warnings: RcList<String>,
3953
}
4054

55+
/// list all the activated versions of a particular crate name from a source
4156
pub type Activations = im_rc::HashMap<(InternedString, SourceId), Rc<Vec<Summary>>>;
4257

4358
impl Context {
44-
pub fn new() -> Context {
59+
pub fn new(check_public_visible_dependencies: bool) -> Context {
4560
Context {
4661
resolve_graph: RcList::new(),
4762
resolve_features: im_rc::HashMap::new(),
4863
links: im_rc::HashMap::new(),
64+
public_dependency: if check_public_visible_dependencies {
65+
Some(im_rc::HashMap::new())
66+
} else {
67+
None
68+
},
69+
parents: Graph::new(),
4970
resolve_replacements: RcList::new(),
5071
activations: im_rc::HashMap::new(),
5172
warnings: RcList::new(),
@@ -147,7 +168,7 @@ impl Context {
147168
pub fn is_conflicting(
148169
&self,
149170
parent: Option<PackageId>,
150-
conflicting_activations: &BTreeMap<PackageId, ConflictReason>,
171+
conflicting_activations: &ConflictMap,
151172
) -> bool {
152173
conflicting_activations
153174
.keys()

src/cargo/core/resolver/errors.rs

+15-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use std::collections::BTreeMap;
21
use std::fmt;
32

43
use crate::core::{Dependency, PackageId, Registry, Summary};
@@ -8,7 +7,7 @@ use failure::{Error, Fail};
87
use semver;
98

109
use super::context::Context;
11-
use super::types::{Candidate, ConflictReason};
10+
use super::types::{Candidate, ConflictMap, ConflictReason};
1211

1312
/// Error during resolution providing a path of `PackageId`s.
1413
pub struct ResolveError {
@@ -73,16 +72,15 @@ pub(super) fn activation_error(
7372
registry: &mut dyn Registry,
7473
parent: &Summary,
7574
dep: &Dependency,
76-
conflicting_activations: &BTreeMap<PackageId, ConflictReason>,
75+
conflicting_activations: &ConflictMap,
7776
candidates: &[Candidate],
7877
config: Option<&Config>,
7978
) -> ResolveError {
80-
let graph = cx.graph();
8179
let to_resolve_err = |err| {
8280
ResolveError::new(
8381
err,
84-
graph
85-
.path_to_top(&parent.package_id())
82+
cx.parents
83+
.path_to_bottom(&parent.package_id())
8684
.into_iter()
8785
.cloned()
8886
.collect(),
@@ -92,7 +90,9 @@ pub(super) fn activation_error(
9290
if !candidates.is_empty() {
9391
let mut msg = format!("failed to select a version for `{}`.", dep.package_name());
9492
msg.push_str("\n ... required by ");
95-
msg.push_str(&describe_path(&graph.path_to_top(&parent.package_id())));
93+
msg.push_str(&describe_path(
94+
&cx.parents.path_to_bottom(&parent.package_id()),
95+
));
9696

9797
msg.push_str("\nversions that meet the requirements `");
9898
msg.push_str(&dep.version_req().to_string());
@@ -123,7 +123,7 @@ pub(super) fn activation_error(
123123
msg.push_str(link);
124124
msg.push_str("` as well:\n");
125125
}
126-
msg.push_str(&describe_path(&graph.path_to_top(p)));
126+
msg.push_str(&describe_path(&cx.parents.path_to_bottom(p)));
127127
}
128128

129129
let (features_errors, other_errors): (Vec<_>, Vec<_>) = other_errors
@@ -154,7 +154,7 @@ pub(super) fn activation_error(
154154

155155
for &(p, _) in other_errors.iter() {
156156
msg.push_str("\n\n previously selected ");
157-
msg.push_str(&describe_path(&graph.path_to_top(p)));
157+
msg.push_str(&describe_path(&cx.parents.path_to_bottom(p)));
158158
}
159159

160160
msg.push_str("\n\nfailed to select a version for `");
@@ -204,7 +204,9 @@ pub(super) fn activation_error(
204204
registry.describe_source(dep.source_id()),
205205
);
206206
msg.push_str("required by ");
207-
msg.push_str(&describe_path(&graph.path_to_top(&parent.package_id())));
207+
msg.push_str(&describe_path(
208+
&cx.parents.path_to_bottom(&parent.package_id()),
209+
));
208210

209211
// If we have a path dependency with a locked version, then this may
210212
// indicate that we updated a sub-package and forgot to run `cargo
@@ -265,7 +267,9 @@ pub(super) fn activation_error(
265267
msg.push_str("\n");
266268
}
267269
msg.push_str("required by ");
268-
msg.push_str(&describe_path(&graph.path_to_top(&parent.package_id())));
270+
msg.push_str(&describe_path(
271+
&cx.parents.path_to_bottom(&parent.package_id()),
272+
));
269273

270274
msg
271275
};

0 commit comments

Comments
 (0)