Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/base-db/src/input.rs')
-rw-r--r--crates/base-db/src/input.rs64
1 files changed, 42 insertions, 22 deletions
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index dfd0b2abc3..e6d265df67 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -9,7 +9,7 @@
use std::{fmt, mem, ops, panic::RefUnwindSafe, str::FromStr, sync::Arc};
use cfg::CfgOptions;
-use la_arena::{Arena, Idx, RawIdx};
+use la_arena::{Arena, Idx};
use rustc_hash::{FxHashMap, FxHashSet};
use syntax::SmolStr;
use tt::token_id::Subtree;
@@ -534,28 +534,46 @@ impl CrateGraph {
Some(crate_id)
}
+ pub fn sort_deps(&mut self) {
+ self.arena
+ .iter_mut()
+ .for_each(|(_, data)| data.dependencies.sort_by_key(|dep| dep.crate_id));
+ }
+
/// Extends this crate graph by adding a complete disjoint second crate
/// graph and adjust the ids in the [`ProcMacroPaths`] accordingly.
///
- /// The ids of the crates in the `other` graph are shifted by the return
- /// amount.
- pub fn extend(&mut self, other: CrateGraph, proc_macros: &mut ProcMacroPaths) -> u32 {
- let start = self.arena.len() as u32;
- self.arena.extend(other.arena.into_iter().map(|(_, mut data)| {
- for dep in &mut data.dependencies {
- dep.crate_id =
- CrateId::from_raw(RawIdx::from(u32::from(dep.crate_id.into_raw()) + start));
+ /// This will deduplicate the crates of the graph where possible.
+ /// Note that for deduplication to fully work, `self`'s crate dependencies must be sorted by crate id.
+ /// If the crate dependencies were sorted, the resulting graph from this `extend` call will also have the crate dependencies sorted.
+ pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) {
+ let topo = other.crates_in_topological_order();
+ let mut id_map: FxHashMap<CrateId, CrateId> = FxHashMap::default();
+
+ for topo in topo {
+ let crate_data = &mut other.arena[topo];
+ crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]);
+ crate_data.dependencies.sort_by_key(|dep| dep.crate_id);
+
+ let res = self.arena.iter().find_map(
+ |(id, data)| {
+ if data == crate_data {
+ Some(id)
+ } else {
+ None
+ }
+ },
+ );
+ if let Some(res) = res {
+ id_map.insert(topo, res);
+ } else {
+ let id = self.arena.alloc(crate_data.clone());
+ id_map.insert(topo, id);
}
- data
- }));
+ }
- *proc_macros = mem::take(proc_macros)
- .into_iter()
- .map(|(id, macros)| {
- (CrateId::from_raw(RawIdx::from(u32::from(id.into_raw()) + start)), macros)
- })
- .collect();
- start
+ *proc_macros =
+ mem::take(proc_macros).into_iter().map(|(id, macros)| (id_map[&id], macros)).collect();
}
fn find_path(
@@ -586,8 +604,10 @@ impl CrateGraph {
// Work around for https://github.com/rust-lang/rust-analyzer/issues/6038.
// As hacky as it gets.
pub fn patch_cfg_if(&mut self) -> bool {
- let cfg_if = self.hacky_find_crate("cfg_if");
- let std = self.hacky_find_crate("std");
+ // we stupidly max by version in an attempt to have all duplicated std's depend on the same cfg_if so that deduplication still works
+ let cfg_if =
+ self.hacky_find_crate("cfg_if").max_by_key(|&it| self.arena[it].version.clone());
+ let std = self.hacky_find_crate("std").next();
match (cfg_if, std) {
(Some(cfg_if), Some(std)) => {
self.arena[cfg_if].dependencies.clear();
@@ -600,8 +620,8 @@ impl CrateGraph {
}
}
- fn hacky_find_crate(&self, display_name: &str) -> Option<CrateId> {
- self.iter().find(|it| self[*it].display_name.as_deref() == Some(display_name))
+ fn hacky_find_crate<'a>(&'a self, display_name: &'a str) -> impl Iterator<Item = CrateId> + 'a {
+ self.iter().filter(move |it| self[*it].display_name.as_deref() == Some(display_name))
}
}