maintain an inverse-index
authorEh2406 <YeomanYaacov@gmail.com>
Wed, 21 Mar 2018 17:09:08 +0000 (13:09 -0400)
committerEh2406 <YeomanYaacov@gmail.com>
Sat, 24 Mar 2018 15:32:14 +0000 (11:32 -0400)
src/cargo/core/resolver/mod.rs

index 726f9557100658c349c5b8dc9d52f50cd50c784a..bd049bd9148c29072c57465b985b3dea6d347268 100644 (file)
@@ -974,7 +974,7 @@ fn activate_deps_loop(
     let mut backtrack_stack = Vec::new();
     let mut remaining_deps = BinaryHeap::new();
 
-    // `past_conflicting_activations`is a cache of the reasons for each time we
+    // `past_conflicting_activations` is a cache of the reasons for each time we
     // backtrack. For example after several backtracks we may have:
     //
     //  past_conflicting_activations[`foo = "^1.0.2"`] = vec![
@@ -1008,6 +1008,10 @@ fn activate_deps_loop(
         Vec<HashMap<PackageId, ConflictReason>>,
     > = HashMap::new();
 
+    // `past_conflict_triggers` is an inverse-index of `past_conflicting_activations`.
+    // For every `PackageId` this lists the `Dependency`s that mention it in `past_conflicting_activations`.
+    let mut past_conflict_triggers: HashMap<PackageId, HashSet<Dependency>> = HashMap::new();
+
     // Activate all the initial summaries to kick off some work.
     for &(ref summary, ref method) in summaries {
         debug!("initial activation: {}", summary.package_id());
@@ -1165,6 +1169,12 @@ fn activate_deps_loop(
                             conflicting_activations
                         );
                         past.push(conflicting_activations.clone());
+                        for c in conflicting_activations.keys() {
+                            past_conflict_triggers
+                                .entry(c.clone())
+                                .or_insert_with(HashSet::new)
+                                .insert(dep.clone());
+                        }
                     }
                 }
 
@@ -1284,22 +1294,27 @@ fn activate_deps_loop(
                         }
                     }
                     if !has_past_conflicting_dep {
-                        // TODO: this is ugly and slow, replace!
-                        'deps: for debs in remaining_deps.iter() {
-                            for (_, (other_dep, _, _)) in debs.remaining_siblings.clone() {
-                                if let Some(conflict) = past_conflicting_activations
-                                    .get(&other_dep)
-                                    .and_then(|past_bad| {
-                                        past_bad
-                                            .iter()
-                                            .find(|conflicting| conflicting.get(&pid).is_some())
-                                    }) {
-                                    conflicting_activations.insert(
-                                        debs.parent.package_id().clone(),
-                                        conflict.get(&pid).unwrap().clone(),
-                                    );
-                                    has_past_conflicting_dep = true;
-                                    break 'deps;
+                        // TODO: this is ugly, replace!
+                        if let Some(rel_deps) = past_conflict_triggers.get(&pid) {
+                            'deps: for debs in remaining_deps.iter() {
+                                for (_, (other_dep, _, _)) in debs.remaining_siblings.clone() {
+                                    if rel_deps.contains(&other_dep) {
+                                        if let Some(conflict) = past_conflicting_activations
+                                            .get(&other_dep)
+                                            .and_then(|past_bad| {
+                                                past_bad.iter().find(|con| {
+                                                    con.contains_key(&pid)
+                                                        && cx.is_conflicting(None, con)
+                                                })
+                                            }) {
+                                            conflicting_activations.insert(
+                                                debs.parent.package_id().clone(),
+                                                conflict.get(&pid).unwrap().clone(),
+                                            );
+                                            has_past_conflicting_dep = true;
+                                            break 'deps;
+                                        }
+                                    }
                                 }
                             }
                         }