]> git.proxmox.com Git - rustc.git/blame - vendor/chalk-solve/src/coherence.rs
New upstream version 1.67.1+dfsg1
[rustc.git] / vendor / chalk-solve / src / coherence.rs
CommitLineData
5099ac24 1use indexmap::IndexMap;
f9f354fc 2use petgraph::prelude::*;
5099ac24 3use rustc_hash::FxHashMap;
f9f354fc 4
3dfed10e 5use crate::solve::Solver;
f9f354fc
XL
6use crate::RustIrDatabase;
7use chalk_ir::interner::Interner;
8use chalk_ir::{self, ImplId, TraitId};
f9f354fc
XL
9use std::fmt;
10use std::sync::Arc;
11
12pub mod orphan;
13mod solve;
14
3dfed10e
XL
15pub struct CoherenceSolver<'a, I: Interner> {
16 db: &'a dyn RustIrDatabase<I>,
17 solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>,
f9f354fc
XL
18 trait_id: TraitId<I>,
19}
20
21#[derive(Debug)]
22pub enum CoherenceError<I: Interner> {
23 OverlappingImpls(TraitId<I>),
24 FailedOrphanCheck(TraitId<I>),
25}
26
27impl<I: Interner> fmt::Display for CoherenceError<I> {
28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
29 match self {
30 CoherenceError::OverlappingImpls(id) => {
31 write!(f, "overlapping impls of trait `{:?}`", id)
32 }
33 CoherenceError::FailedOrphanCheck(id) => {
34 write!(f, "impl for trait `{:?}` violates the orphan rules", id)
35 }
36 }
37 }
38}
39
40impl<I: Interner> std::error::Error for CoherenceError<I> {}
41
42/// Stores the specialization priorities for a set of impls.
43/// This basically encodes which impls specialize one another.
44#[derive(Clone, Debug, Default, PartialEq, Eq)]
45pub struct SpecializationPriorities<I: Interner> {
5099ac24 46 map: IndexMap<ImplId<I>, SpecializationPriority>,
f9f354fc
XL
47}
48
49impl<I: Interner> SpecializationPriorities<I> {
50 pub fn new() -> Self {
51 Self {
5099ac24 52 map: IndexMap::new(),
f9f354fc
XL
53 }
54 }
55
56 /// Lookup the priority of an impl in the set (panics if impl is not in set).
57 pub fn priority(&self, impl_id: ImplId<I>) -> SpecializationPriority {
58 self.map[&impl_id]
59 }
60
61 /// Store the priority of an impl (used during construction).
62 /// Panics if we have already stored the priority for this impl.
63 fn insert(&mut self, impl_id: ImplId<I>, p: SpecializationPriority) {
64 let old_value = self.map.insert(impl_id, p);
65 assert!(old_value.is_none());
66 }
67}
68
69/// Impls with higher priority take precedence over impls with lower
70/// priority (if both apply to the same types). Impls with equal
71/// priority should never apply to the same set of input types.
72#[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)]
73pub struct SpecializationPriority(usize);
74
3dfed10e 75impl<'a, I> CoherenceSolver<'a, I>
f9f354fc
XL
76where
77 I: Interner,
78{
79 /// Constructs a new `CoherenceSolver`.
80 pub fn new(
3dfed10e
XL
81 db: &'a dyn RustIrDatabase<I>,
82 solver_builder: &'a dyn Fn() -> Box<dyn Solver<I>>,
f9f354fc
XL
83 trait_id: TraitId<I>,
84 ) -> Self {
85 Self {
86 db,
3dfed10e 87 solver_builder,
f9f354fc
XL
88 trait_id,
89 }
90 }
91
92 pub fn specialization_priorities(
93 &self,
94 ) -> Result<Arc<SpecializationPriorities<I>>, CoherenceError<I>> {
95 let mut result = SpecializationPriorities::<I>::new();
96
97 let forest = self.build_specialization_forest()?;
98
487cf647 99 // TypeVisitable every root in the forest & set specialization
f9f354fc
XL
100 // priority for the tree that is the root of.
101 for root_idx in forest.externals(Direction::Incoming) {
102 self.set_priorities(root_idx, &forest, 0, &mut result);
103 }
104
105 Ok(Arc::new(result))
106 }
107
108 // Build the forest of specialization relationships.
109 fn build_specialization_forest(&self) -> Result<Graph<ImplId<I>, ()>, CoherenceError<I>> {
5099ac24
FG
110 let mut forest = DiGraph::new();
111 let mut node_map = FxHashMap::default();
f9f354fc 112
5099ac24
FG
113 // Find all specializations. Record them in the forest
114 // by adding an edge from the less special to the more special.
f9f354fc 115 self.visit_specializations_of_trait(|less_special, more_special| {
5099ac24
FG
116 let less_special_node = *node_map
117 .entry(less_special)
118 .or_insert_with(|| forest.add_node(less_special));
119 let more_special_node = *node_map
120 .entry(more_special)
121 .or_insert_with(|| forest.add_node(more_special));
122 forest.update_edge(less_special_node, more_special_node, ());
f9f354fc
XL
123 })?;
124
5099ac24 125 Ok(forest)
f9f354fc
XL
126 }
127
128 // Recursively set priorities for those node and all of its children.
129 fn set_priorities(
130 &self,
131 idx: NodeIndex,
132 forest: &Graph<ImplId<I>, ()>,
133 p: usize,
134 map: &mut SpecializationPriorities<I>,
135 ) {
136 // Get the impl datum recorded at this node and reset its priority
137 {
138 let impl_id = forest
139 .node_weight(idx)
140 .expect("index should be a valid index into graph");
141 map.insert(*impl_id, SpecializationPriority(p));
142 }
143
487cf647 144 // TypeVisitable all children of this node, setting their priority to this + 1
f9f354fc
XL
145 for child_idx in forest.neighbors(idx) {
146 self.set_priorities(child_idx, forest, p + 1, map);
147 }
148 }
149}