Skip to content

Commit e3b7f2f

Browse files
committed
Fix caching features across backtracking
In the local loop during resolution all variables need to be reset whenever we backtrack up a frame, but currently the `method` and `features` set are accidentally not reset whenever we backtrack. Calculate the `method` later and cache `features` in each frame so we can properly backtrack. Closes #2472
1 parent c3b571f commit e3b7f2f

File tree

4 files changed

+107
-42
lines changed

4 files changed

+107
-42
lines changed

src/cargo/core/resolver/mod.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@ struct BacktrackFrame {
275275
remaining_candidates: RcVecIter<Rc<Summary>>,
276276
parent: Rc<Summary>,
277277
dep: Dependency,
278+
features: Vec<String>,
278279
}
279280

280281
/// Recursively activates the dependencies for `top`, in depth-first order,
@@ -319,15 +320,9 @@ fn activate_deps_loop(mut cx: Context,
319320
}
320321
None => continue,
321322
};
322-
let (mut parent, (mut cur, (mut dep, candidates, features))) = frame;
323+
let (mut parent, (mut cur, (mut dep, candidates, mut features))) = frame;
323324
assert!(!remaining_deps.is_empty());
324325

325-
let method = Method::Required {
326-
dev_deps: false,
327-
features: &features,
328-
uses_default_features: dep.uses_default_features(),
329-
};
330-
331326
let my_candidates = {
332327
let prev_active = cx.prev_active(&dep);
333328
trace!("{}[{}]>{} {} candidates", parent.name(), cur, dep.name(),
@@ -373,6 +368,7 @@ fn activate_deps_loop(mut cx: Context,
373368
remaining_candidates: remaining_candidates,
374369
parent: parent.clone(),
375370
dep: dep.clone(),
371+
features: features.clone(),
376372
});
377373
candidate
378374
}
@@ -383,9 +379,13 @@ fn activate_deps_loop(mut cx: Context,
383379
// their state at the found level of the `backtrack_stack`.
384380
trace!("{}[{}]>{} -- no candidates", parent.name(), cur,
385381
dep.name());
386-
match find_candidate(&mut backtrack_stack, &mut cx,
387-
&mut remaining_deps, &mut parent, &mut cur,
388-
&mut dep) {
382+
match find_candidate(&mut backtrack_stack,
383+
&mut cx,
384+
&mut remaining_deps,
385+
&mut parent,
386+
&mut cur,
387+
&mut dep,
388+
&mut features) {
389389
None => return Err(activation_error(&cx, registry, &parent,
390390
&dep,
391391
&cx.prev_active(&dep),
@@ -395,6 +395,11 @@ fn activate_deps_loop(mut cx: Context,
395395
}
396396
};
397397

398+
let method = Method::Required {
399+
dev_deps: false,
400+
features: &features,
401+
uses_default_features: dep.uses_default_features(),
402+
};
398403
trace!("{}[{}]>{} trying {}", parent.name(), cur, dep.name(),
399404
candidate.version());
400405
cx.resolve.graph.link(parent.package_id().clone(),
@@ -414,14 +419,16 @@ fn find_candidate(backtrack_stack: &mut Vec<BacktrackFrame>,
414419
remaining_deps: &mut BinaryHeap<DepsFrame>,
415420
parent: &mut Rc<Summary>,
416421
cur: &mut usize,
417-
dep: &mut Dependency) -> Option<Rc<Summary>> {
422+
dep: &mut Dependency,
423+
features: &mut Vec<String>) -> Option<Rc<Summary>> {
418424
while let Some(mut frame) = backtrack_stack.pop() {
419425
if let Some((_, candidate)) = frame.remaining_candidates.next() {
420426
*cx = frame.context_backup.clone();
421427
*remaining_deps = frame.deps_backup.clone();
422428
*parent = frame.parent.clone();
423429
*cur = remaining_deps.peek().unwrap().remaining_siblings.cur_index();
424430
*dep = frame.dep.clone();
431+
*features = frame.features.clone();
425432
backtrack_stack.push(frame);
426433
return Some(candidate)
427434
}

tests/support/registry.rs

Lines changed: 64 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::collections::HashMap;
12
use std::fs::{self, File};
23
use std::io::prelude::*;
34
use std::path::{PathBuf, Path};
@@ -6,6 +7,7 @@ use flate2::Compression::Default;
67
use flate2::write::GzEncoder;
78
use git2;
89
use rustc_serialize::hex::ToHex;
10+
use rustc_serialize::json::ToJson;
911
use tar::{Builder, Header};
1012
use url::Url;
1113

@@ -21,9 +23,18 @@ pub fn dl_url() -> Url { Url::from_file_path(&*dl_path()).ok().unwrap() }
2123
pub struct Package {
2224
name: String,
2325
vers: String,
24-
deps: Vec<(String, String, &'static str, String)>,
26+
deps: Vec<Dependency>,
2527
files: Vec<(String, String)>,
2628
yanked: bool,
29+
features: HashMap<String, Vec<String>>,
30+
}
31+
32+
struct Dependency {
33+
name: String,
34+
vers: String,
35+
kind: String,
36+
target: Option<String>,
37+
features: Vec<String>,
2738
}
2839

2940
fn init() {
@@ -55,6 +66,7 @@ impl Package {
5566
deps: Vec::new(),
5667
files: Vec::new(),
5768
yanked: false,
69+
features: HashMap::new(),
5870
}
5971
}
6072

@@ -64,23 +76,40 @@ impl Package {
6476
}
6577

6678
pub fn dep(&mut self, name: &str, vers: &str) -> &mut Package {
67-
self.deps.push((name.to_string(), vers.to_string(), "normal",
68-
"null".to_string()));
69-
self
79+
self.full_dep(name, vers, None, "normal", &[])
80+
}
81+
82+
pub fn feature_dep(&mut self,
83+
name: &str,
84+
vers: &str,
85+
features: &[&str]) -> &mut Package {
86+
self.full_dep(name, vers, None, "normal", features)
7087
}
7188

7289
pub fn target_dep(&mut self,
7390
name: &str,
7491
vers: &str,
7592
target: &str) -> &mut Package {
76-
self.deps.push((name.to_string(), vers.to_string(), "normal",
77-
format!("\"{}\"", target)));
78-
self
93+
self.full_dep(name, vers, Some(target), "normal", &[])
7994
}
8095

8196
pub fn dev_dep(&mut self, name: &str, vers: &str) -> &mut Package {
82-
self.deps.push((name.to_string(), vers.to_string(), "dev",
83-
"null".to_string()));
97+
self.full_dep(name, vers, None, "dev", &[])
98+
}
99+
100+
fn full_dep(&mut self,
101+
name: &str,
102+
vers: &str,
103+
target: Option<&str>,
104+
kind: &str,
105+
features: &[&str]) -> &mut Package {
106+
self.deps.push(Dependency {
107+
name: name.to_string(),
108+
vers: vers.to_string(),
109+
kind: kind.to_string(),
110+
target: target.map(|s| s.to_string()),
111+
features: features.iter().map(|s| s.to_string()).collect(),
112+
});
84113
self
85114
}
86115

@@ -89,30 +118,36 @@ impl Package {
89118
self
90119
}
91120

92-
#[allow(deprecated)] // connect => join in 1.3
93121
pub fn publish(&self) {
94122
self.make_archive();
95123

96124
// Figure out what we're going to write into the index
97-
let deps = self.deps.iter().map(|&(ref name, ref req, ref kind, ref target)| {
98-
format!("{{\"name\":\"{}\",\
99-
\"req\":\"{}\",\
100-
\"features\":[],\
101-
\"default_features\":false,\
102-
\"target\":{},\
103-
\"optional\":false,\
104-
\"kind\":\"{}\"}}", name, req, target, kind)
105-
}).collect::<Vec<_>>().connect(",");
125+
let deps = self.deps.iter().map(|dep| {
126+
let mut map = HashMap::new();
127+
map.insert("name".to_string(), dep.name.to_json());
128+
map.insert("req".to_string(), dep.vers.to_json());
129+
map.insert("features".to_string(), dep.features.to_json());
130+
map.insert("default_features".to_string(), false.to_json());
131+
map.insert("target".to_string(), dep.target.to_json());
132+
map.insert("optional".to_string(), false.to_json());
133+
map.insert("kind".to_string(), dep.kind.to_json());
134+
map
135+
}).collect::<Vec<_>>();
106136
let cksum = {
107137
let mut c = Vec::new();
108138
File::open(&self.archive_dst()).unwrap()
109139
.read_to_end(&mut c).unwrap();
110140
cksum(&c)
111141
};
112-
let line = format!("{{\"name\":\"{}\",\"vers\":\"{}\",\
113-
\"deps\":[{}],\"cksum\":\"{}\",\"features\":{{}},\
114-
\"yanked\":{}}}",
115-
self.name, self.vers, deps, cksum, self.yanked);
142+
let mut dep = HashMap::new();
143+
dep.insert("name".to_string(), self.name.to_json());
144+
dep.insert("vers".to_string(), self.vers.to_json());
145+
dep.insert("deps".to_string(), deps.to_json());
146+
dep.insert("cksum".to_string(), cksum.to_json());
147+
dep.insert("features".to_string(), self.features.to_json());
148+
dep.insert("yanked".to_string(), self.yanked.to_json());
149+
let line = dep.to_json().to_string();
150+
116151
let file = match self.name.len() {
117152
1 => format!("1/{}", self.name),
118153
2 => format!("2/{}", self.name),
@@ -152,20 +187,20 @@ impl Package {
152187
version = "{}"
153188
authors = []
154189
"#, self.name, self.vers);
155-
for &(ref dep, ref req, kind, ref target) in self.deps.iter() {
156-
let target = match &target[..] {
157-
"null" => String::new(),
158-
t => format!("target.{}.", t),
190+
for dep in self.deps.iter() {
191+
let target = match dep.target {
192+
None => String::new(),
193+
Some(ref s) => format!("target.{}.", s),
159194
};
160-
let kind = match kind {
195+
let kind = match &dep.kind[..] {
161196
"build" => "build-",
162197
"dev" => "dev-",
163198
_ => ""
164199
};
165200
manifest.push_str(&format!(r#"
166201
[{}{}dependencies.{}]
167202
version = "{}"
168-
"#, target, kind, dep, req));
203+
"#, target, kind, dep.name, dep.vers));
169204
}
170205

171206
let dst = self.archive_dst();

tests/test_cargo_cfg.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ test!(works_through_the_registry {
194194

195195
Package::new("foo", "0.1.0").publish();
196196
Package::new("bar", "0.1.0")
197-
.target_dep("foo", "0.1.0", "cfg(unix)")
198-
.target_dep("foo", "0.1.0", "cfg(windows)")
197+
.target_dep("foo", "0.1.0", "'cfg(unix)'")
198+
.target_dep("foo", "0.1.0", "'cfg(windows)'")
199199
.publish();
200200

201201
let p = project("a")

tests/test_cargo_registry.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,3 +1015,26 @@ test!(only_download_relevant {
10151015
{compiling} bar v0.5.0 ([..])
10161016
", downloading = DOWNLOADING, compiling = COMPILING, updating = UPDATING)));
10171017
});
1018+
1019+
test!(resolve_and_backtracking {
1020+
let p = project("foo")
1021+
.file("Cargo.toml", r#"
1022+
[project]
1023+
name = "bar"
1024+
version = "0.5.0"
1025+
authors = []
1026+
1027+
[dependencies]
1028+
foo = "*"
1029+
"#)
1030+
.file("src/main.rs", "fn main() {}");
1031+
p.build();
1032+
1033+
Package::new("foo", "0.1.1")
1034+
.feature_dep("bar", "0.1", &["a", "b"])
1035+
.publish();
1036+
Package::new("foo", "0.1.0").publish();
1037+
1038+
assert_that(p.cargo("build"),
1039+
execs().with_status(0));
1040+
});

0 commit comments

Comments
 (0)