Skip to main content

pilota_build/middle/
type_graph.rs

1use std::sync::Arc;
2
3use petgraph::{Graph, algo::has_path_connecting, graph::NodeIndex};
4use rustc_hash::FxHashMap;
5
6use super::{
7    rir::Item,
8    ty::{self},
9};
10use crate::symbol::DefId;
11
12#[derive(Debug)]
13pub struct TypeGraph {
14    pub(crate) graph: Graph<DefId, ()>,
15    pub(crate) node_map: FxHashMap<DefId, NodeIndex>,
16}
17
18impl TypeGraph {
19    pub fn from_items(items: impl Iterator<Item = (DefId, Arc<Item>)> + Clone) -> Self {
20        let mut graph: Graph<DefId, ()> = Graph::new();
21        let mut node_map = FxHashMap::default();
22        items.clone().for_each(|(def_id, _)| {
23            let node_index = graph.add_node(def_id);
24            node_map.insert(def_id, node_index);
25        });
26
27        items.for_each(|(def_id, item)| {
28            let idx = node_map[&def_id];
29            match &*item {
30                Item::Message(s) => s.fields.iter().for_each(|f| {
31                    if let ty::Path(p) = &f.ty.kind {
32                        graph.add_edge(idx, node_map[&p.did], ());
33                    }
34                }),
35                Item::Enum(e) => {
36                    e.variants.iter().flat_map(|v| &v.fields).for_each(|ty| {
37                        if let ty::Path(p) = &ty.kind {
38                            graph.add_edge(idx, node_map[&p.did], ());
39                        }
40                    });
41                }
42                Item::NewType(t) => {
43                    if let ty::Path(p) = &t.ty.kind {
44                        graph.add_edge(idx, node_map[&p.did], ());
45                    }
46                }
47                _ => {}
48            };
49        });
50        Self { graph, node_map }
51    }
52
53    pub fn is_nested(&self, a: DefId, b: DefId) -> bool {
54        let a = self.node_map[&a];
55        let b = self.node_map[&b];
56        has_path_connecting(&self.graph, a, b, None)
57    }
58
59    pub fn is_cycled(&self, a: DefId) -> bool {
60        let a = self.node_map[&a];
61        for n in self
62            .graph
63            .neighbors_directed(a, petgraph::Direction::Outgoing)
64        {
65            if has_path_connecting(&self.graph, n, a, None) {
66                return true;
67            }
68        }
69        false
70    }
71}