diff --git a/Cargo.lock b/Cargo.lock index d6d60bd5d3f..5fdf3e898fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -142,6 +142,7 @@ dependencies = [ "chalk-parse", "chalk-recursive", "chalk-solve", + "indexmap", "salsa", "string_cache", "tracing", @@ -186,6 +187,7 @@ dependencies = [ "chalk-integration", "chalk-ir", "ena", + "indexmap", "itertools", "petgraph", "rustc-hash", diff --git a/chalk-integration/Cargo.toml b/chalk-integration/Cargo.toml index 00c39f13cc6..8431b370e62 100644 --- a/chalk-integration/Cargo.toml +++ b/chalk-integration/Cargo.toml @@ -20,3 +20,4 @@ chalk-solve = { version = "0.76.0-dev.0", path = "../chalk-solve" } chalk-recursive = { version = "0.76.0-dev.0", path = "../chalk-recursive" } chalk-engine = { version = "0.76.0-dev.0", path = "../chalk-engine" } chalk-parse = { version = "0.76.0-dev.0", path = "../chalk-parse" } +indexmap = "1.7.0" diff --git a/chalk-ir/src/interner.rs b/chalk-ir/src/interner.rs index 7c80faf8cf1..f8b3c58980f 100644 --- a/chalk-ir/src/interner.rs +++ b/chalk-ir/src/interner.rs @@ -57,7 +57,7 @@ use std::sync::Arc; /// (e.g., `SourceI` and `TargetI`) -- even if those type parameters /// wind up being mapped to the same underlying type families in the /// end. -pub trait Interner: Debug + Copy + Eq + Ord + Hash + Sized { +pub trait Interner: Debug + Copy + Eq + Hash + Sized { /// "Interned" representation of types. In normal user code, /// `Self::InternedType` is not referenced. Instead, we refer to /// `Ty`, which wraps this type. @@ -188,10 +188,10 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash + Sized { type InternedVariances: Debug + Clone + Eq + Hash; /// The core "id" type used for trait-ids and the like. - type DefId: Debug + Copy + Eq + Ord + Hash; + type DefId: Debug + Copy + Eq + Hash; /// The ID type for ADTs - type InternedAdtId: Debug + Copy + Eq + Ord + Hash; + type InternedAdtId: Debug + Copy + Eq + Hash; /// Representation of identifiers. type Identifier: Debug + Clone + Eq + Hash; diff --git a/chalk-solve/Cargo.toml b/chalk-solve/Cargo.toml index 90dc589f15f..756e9010143 100644 --- a/chalk-solve/Cargo.toml +++ b/chalk-solve/Cargo.toml @@ -20,6 +20,7 @@ rustc-hash = { version = "1.1.0" } chalk-derive = { version = "0.76.0-dev.0", path = "../chalk-derive" } chalk-ir = { version = "0.76.0-dev.0", path = "../chalk-ir" } +indexmap = "1.7.0" [dev-dependencies] chalk-integration = { path = "../chalk-integration" } diff --git a/chalk-solve/src/coherence.rs b/chalk-solve/src/coherence.rs index 31384c0d82c..20759dacea6 100644 --- a/chalk-solve/src/coherence.rs +++ b/chalk-solve/src/coherence.rs @@ -1,10 +1,11 @@ +use indexmap::IndexMap; use petgraph::prelude::*; +use rustc_hash::FxHashMap; use crate::solve::Solver; use crate::RustIrDatabase; use chalk_ir::interner::Interner; use chalk_ir::{self, ImplId, TraitId}; -use std::collections::BTreeMap; use std::fmt; use std::sync::Arc; @@ -42,13 +43,13 @@ impl std::error::Error for CoherenceError {} /// This basically encodes which impls specialize one another. #[derive(Clone, Debug, Default, PartialEq, Eq)] pub struct SpecializationPriorities { - map: BTreeMap, SpecializationPriority>, + map: IndexMap, SpecializationPriority>, } impl SpecializationPriorities { pub fn new() -> Self { Self { - map: BTreeMap::new(), + map: IndexMap::new(), } } @@ -106,18 +107,22 @@ where // Build the forest of specialization relationships. fn build_specialization_forest(&self) -> Result, ()>, CoherenceError> { - // The forest is returned as a graph but built as a GraphMap; this is - // so that we never add multiple nodes with the same ItemId. - let mut forest = DiGraphMap::new(); + let mut forest = DiGraph::new(); + let mut node_map = FxHashMap::default(); - // Find all specializations (implemented in coherence/solve) - // Record them in the forest by adding an edge from the less special - // to the more special. + // Find all specializations. Record them in the forest + // by adding an edge from the less special to the more special. self.visit_specializations_of_trait(|less_special, more_special| { - forest.add_edge(less_special, more_special, ()); + let less_special_node = *node_map + .entry(less_special) + .or_insert_with(|| forest.add_node(less_special)); + let more_special_node = *node_map + .entry(more_special) + .or_insert_with(|| forest.add_node(more_special)); + forest.update_edge(less_special_node, more_special_node, ()); })?; - Ok(forest.into_graph()) + Ok(forest) } // Recursively set priorities for those node and all of its children. diff --git a/chalk-solve/src/display/state.rs b/chalk-solve/src/display/state.rs index d12373de31c..fed2f5ca599 100644 --- a/chalk-solve/src/display/state.rs +++ b/chalk-solve/src/display/state.rs @@ -1,6 +1,7 @@ //! Persistent state passed down between writers. //! //! This is essentially `InternalWriterState` and other things supporting that. +use core::hash::Hash; use std::{ borrow::Borrow, collections::BTreeMap, @@ -12,6 +13,7 @@ use std::{ use crate::RustIrDatabase; use chalk_ir::{interner::Interner, *}; +use indexmap::IndexMap; use itertools::Itertools; /// Like a BoundVar, but with the debrujin index inverted so as to create a @@ -36,31 +38,31 @@ impl Display for InvertedBoundVar { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] enum UnifiedId { AdtId(I::InternedAdtId), DefId(I::DefId), } #[derive(Debug)] -pub struct IdAliasStore { +pub struct IdAliasStore { /// Map from the DefIds we've encountered to a u32 alias id unique to all ids /// the same name. - aliases: BTreeMap, + aliases: IndexMap, /// Map from each name to the next unused u32 alias id. next_unused_for_name: BTreeMap, } -impl Default for IdAliasStore { +impl Default for IdAliasStore { fn default() -> Self { IdAliasStore { - aliases: BTreeMap::default(), + aliases: IndexMap::default(), next_unused_for_name: BTreeMap::default(), } } } -impl IdAliasStore { +impl IdAliasStore { fn alias_for_id_name(&mut self, id: T, name: String) -> String { let next_unused_for_name = &mut self.next_unused_for_name; let alias = *self.aliases.entry(id).or_insert_with(|| { diff --git a/chalk-solve/src/logging_db.rs b/chalk-solve/src/logging_db.rs index 15fdfadc2a5..00408a28a0c 100644 --- a/chalk-solve/src/logging_db.rs +++ b/chalk-solve/src/logging_db.rs @@ -2,8 +2,6 @@ //! `.chalk` files containing those definitions. use std::{ borrow::Borrow, - cmp::{Ord, Ordering}, - collections::BTreeSet, fmt::{self, Debug, Display}, io::Write, marker::PhantomData, @@ -18,6 +16,8 @@ use crate::{ }; use chalk_ir::{interner::Interner, *}; +use indexmap::IndexSet; + mod id_collector; /// Wraps another `RustIrDatabase` (`DB`) and records which definitions are @@ -36,7 +36,7 @@ where I: Interner, { ws: WriterState, - def_ids: Mutex>>, + def_ids: Mutex>>, _phantom: PhantomData, } @@ -535,7 +535,7 @@ where } } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum RecordedItemId { Adt(AdtId), Trait(TraitId), @@ -580,38 +580,3 @@ impl From> for RecordedItemId { RecordedItemId::Generator(v) } } - -/// Utility for implementing Ord for RecordedItemId. -#[derive(PartialEq, Eq, PartialOrd, Ord)] -enum OrderedItemId<'a, DefId, AdtId> { - DefId(&'a DefId), - AdtId(&'a AdtId), -} - -impl RecordedItemId { - /// Extract internal identifier. Allows for absolute ordering matching the - /// order in which chalk saw things (and thus reproducing that order in - /// printed programs) - fn ordered_item_id(&self) -> OrderedItemId<'_, I::DefId, I::InternedAdtId> { - match self { - RecordedItemId::Trait(TraitId(x)) - | RecordedItemId::Impl(ImplId(x)) - | RecordedItemId::OpaqueTy(OpaqueTyId(x)) - | RecordedItemId::Generator(GeneratorId(x)) - | RecordedItemId::FnDef(FnDefId(x)) => OrderedItemId::DefId(x), - RecordedItemId::Adt(AdtId(x)) => OrderedItemId::AdtId(x), - } - } -} - -impl PartialOrd for RecordedItemId { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for RecordedItemId { - fn cmp(&self, other: &Self) -> Ordering { - self.ordered_item_id().cmp(&other.ordered_item_id()) - } -} diff --git a/chalk-solve/src/logging_db/id_collector.rs b/chalk-solve/src/logging_db/id_collector.rs index f406b8b9a1e..603b4800b05 100644 --- a/chalk-solve/src/logging_db/id_collector.rs +++ b/chalk-solve/src/logging_db/id_collector.rs @@ -6,9 +6,10 @@ use chalk_ir::{ visit::{SuperVisit, Visit}, AliasTy, DebruijnIndex, TyKind, WhereClause, }; -use std::collections::BTreeSet; use std::ops::ControlFlow; +use indexmap::IndexSet; + /// Collects the identifiers needed to resolve all the names for a given /// set of identifers, excluding identifiers we already have. /// @@ -34,11 +35,11 @@ use std::ops::ControlFlow; /// resolution is successful. pub fn collect_unrecorded_ids<'i, I: Interner, DB: RustIrDatabase>( db: &'i DB, - identifiers: &'_ BTreeSet>, -) -> BTreeSet> { + identifiers: &'_ IndexSet>, +) -> IndexSet> { let mut collector = IdCollector { db, - found_identifiers: BTreeSet::new(), + found_identifiers: IndexSet::new(), }; for id in identifiers { match *id { @@ -96,7 +97,7 @@ pub fn collect_unrecorded_ids<'i, I: Interner, DB: RustIrDatabase>( struct IdCollector<'i, I: Interner, DB: RustIrDatabase> { db: &'i DB, - found_identifiers: BTreeSet>, + found_identifiers: IndexSet>, } impl<'i, I: Interner, DB: RustIrDatabase> IdCollector<'i, I, DB> {