pilota_build/middle/
type_graph.rs1use 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}