1 use rustc_data_structures::graph::{
2 self, DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors,
4 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
5 use rustc_data_structures::sync::OnceCell;
6 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
8 /// Helper type to cache the result of `graph::is_cyclic`.
9 #[derive(Clone, Debug)]
10 pub(super) struct GraphIsCyclicCache {
11 cache: OnceCell<bool>,
14 impl GraphIsCyclicCache {
16 pub(super) fn new() -> Self {
17 GraphIsCyclicCache { cache: OnceCell::new() }
20 pub(super) fn is_cyclic<G>(&self, graph: &G) -> bool
22 G: ?Sized + DirectedGraph + WithStartNode + WithSuccessors + WithNumNodes,
24 *self.cache.get_or_init(|| graph::is_cyclic(graph))
27 /// Invalidates the cache.
29 pub(super) fn invalidate(&mut self) {
30 // Invalidating the cache requires mutating the MIR, which in turn requires a unique
31 // reference (`&mut`) to the `mir::Body`. Because of this, we can assume that all
32 // callers of `invalidate` have a unique reference to the MIR and thus to the
33 // cache. This means we never need to do synchronization when `invalidate` is called,
34 // we can simply reinitialize the `OnceCell`.
35 self.cache = OnceCell::new();
39 impl<S: Encoder> Encodable<S> for GraphIsCyclicCache {
41 fn encode(&self, s: &mut S) {
42 Encodable::encode(&(), s);
46 impl<D: Decoder> Decodable<D> for GraphIsCyclicCache {
48 fn decode(d: &mut D) -> Self {
49 let () = Decodable::decode(d);
54 impl<CTX> HashStable<CTX> for GraphIsCyclicCache {
56 fn hash_stable(&self, _: &mut CTX, _: &mut StableHasher) {
61 TrivialTypeTraversalAndLiftImpls! {