]>
git.proxmox.com Git - rustc.git/blob - vendor/chalk-solve/src/coherence.rs
1 use petgraph
::prelude
::*;
3 use crate::solve
::Solver
;
4 use crate::RustIrDatabase
;
5 use chalk_ir
::interner
::Interner
;
6 use chalk_ir
::{self, ImplId, TraitId}
;
7 use std
::collections
::BTreeMap
;
14 pub struct CoherenceSolver
<'a
, I
: Interner
> {
15 db
: &'a
dyn RustIrDatabase
<I
>,
16 solver_builder
: &'a
dyn Fn() -> Box
<dyn Solver
<I
>>,
21 pub enum CoherenceError
<I
: Interner
> {
22 OverlappingImpls(TraitId
<I
>),
23 FailedOrphanCheck(TraitId
<I
>),
26 impl<I
: Interner
> fmt
::Display
for CoherenceError
<I
> {
27 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
29 CoherenceError
::OverlappingImpls(id
) => {
30 write
!(f
, "overlapping impls of trait `{:?}`", id
)
32 CoherenceError
::FailedOrphanCheck(id
) => {
33 write
!(f
, "impl for trait `{:?}` violates the orphan rules", id
)
39 impl<I
: Interner
> std
::error
::Error
for CoherenceError
<I
> {}
41 /// Stores the specialization priorities for a set of impls.
42 /// This basically encodes which impls specialize one another.
43 #[derive(Clone, Debug, Default, PartialEq, Eq)]
44 pub struct SpecializationPriorities
<I
: Interner
> {
45 map
: BTreeMap
<ImplId
<I
>, SpecializationPriority
>,
48 impl<I
: Interner
> SpecializationPriorities
<I
> {
49 pub fn new() -> Self {
55 /// Lookup the priority of an impl in the set (panics if impl is not in set).
56 pub fn priority(&self, impl_id
: ImplId
<I
>) -> SpecializationPriority
{
60 /// Store the priority of an impl (used during construction).
61 /// Panics if we have already stored the priority for this impl.
62 fn insert(&mut self, impl_id
: ImplId
<I
>, p
: SpecializationPriority
) {
63 let old_value
= self.map
.insert(impl_id
, p
);
64 assert
!(old_value
.is_none());
68 /// Impls with higher priority take precedence over impls with lower
69 /// priority (if both apply to the same types). Impls with equal
70 /// priority should never apply to the same set of input types.
71 #[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)]
72 pub struct SpecializationPriority(usize);
74 impl<'a
, I
> CoherenceSolver
<'a
, I
>
78 /// Constructs a new `CoherenceSolver`.
80 db
: &'a
dyn RustIrDatabase
<I
>,
81 solver_builder
: &'a
dyn Fn() -> Box
<dyn Solver
<I
>>,
91 pub fn specialization_priorities(
93 ) -> Result
<Arc
<SpecializationPriorities
<I
>>, CoherenceError
<I
>> {
94 let mut result
= SpecializationPriorities
::<I
>::new();
96 let forest
= self.build_specialization_forest()?
;
98 // Visit every root in the forest & set specialization
99 // priority for the tree that is the root of.
100 for root_idx
in forest
.externals(Direction
::Incoming
) {
101 self.set_priorities(root_idx
, &forest
, 0, &mut result
);
107 // Build the forest of specialization relationships.
108 fn build_specialization_forest(&self) -> Result
<Graph
<ImplId
<I
>, ()>, CoherenceError
<I
>> {
109 // The forest is returned as a graph but built as a GraphMap; this is
110 // so that we never add multiple nodes with the same ItemId.
111 let mut forest
= DiGraphMap
::new();
113 // Find all specializations (implemented in coherence/solve)
114 // Record them in the forest by adding an edge from the less special
115 // to the more special.
116 self.visit_specializations_of_trait(|less_special
, more_special
| {
117 forest
.add_edge(less_special
, more_special
, ());
120 Ok(forest
.into_graph())
123 // Recursively set priorities for those node and all of its children.
127 forest
: &Graph
<ImplId
<I
>, ()>,
129 map
: &mut SpecializationPriorities
<I
>,
131 // Get the impl datum recorded at this node and reset its priority
135 .expect("index should be a valid index into graph");
136 map
.insert(*impl_id
, SpecializationPriority(p
));
139 // Visit all children of this node, setting their priority to this + 1
140 for child_idx
in forest
.neighbors(idx
) {
141 self.set_priorities(child_idx
, forest
, p
+ 1, map
);