flux_middle/rty/
spec_func.rs1use std::ops::ControlFlow;
2
3use itertools::Itertools;
4use rustc_data_structures::{
5 fx::{FxIndexMap, FxIndexSet},
6 unord::UnordMap,
7};
8use rustc_hir::def_id::DefIndex;
9use rustc_macros::{TyDecodable, TyEncodable};
10use toposort_scc::IndexGraph;
11
12use crate::{
13 def_id::{FluxDefId, FluxId, FluxLocalDefId},
14 rty::{
15 Binder, Expr, ExprKind,
16 expr::SpecFuncKind,
17 fold::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
18 },
19};
20
21#[derive(Clone, TyEncodable, TyDecodable)]
24pub enum SpecFunc {
25 Uif,
27 Defined {
29 body: Binder<Expr>,
30 hide: bool,
32 },
33}
34
35impl SpecFunc {
36 pub fn is_uif(&self) -> bool {
37 matches!(self, SpecFunc::Uif)
38 }
39}
40
41#[derive(Default, TyEncodable, TyDecodable)]
49pub struct SpecFuncs {
50 funcs: FxIndexMap<FluxId<DefIndex>, SpecFunc>,
51}
52
53impl SpecFuncs {
54 pub fn new(funcs: Vec<(FluxLocalDefId, SpecFunc)>) -> Result<Self, Vec<FluxLocalDefId>> {
57 let order = toposort(&funcs)?;
58 let mut funcs = funcs.into_iter().map(Some).collect_vec();
59 let funcs = order
60 .into_iter()
61 .map(|i| {
62 let (id, func) = funcs[i].take().unwrap();
63 (id.local_def_index(), func)
64 })
65 .collect();
66 Ok(Self { funcs })
67 }
68
69 pub fn get(&self, id: FluxId<DefIndex>) -> &SpecFunc {
70 &self.funcs[&id]
71 }
72
73 pub fn rank(&self, id: FluxId<DefIndex>) -> usize {
76 self.funcs.get_index_of(&id).unwrap()
77 }
78}
79
80fn toposort(funcs: &[(FluxLocalDefId, SpecFunc)]) -> Result<Vec<usize>, Vec<FluxLocalDefId>> {
85 let s2i: UnordMap<FluxDefId, usize> = funcs
87 .iter()
88 .enumerate()
89 .map(|(i, (id, _))| (id.to_def_id(), i))
90 .collect();
91
92 let mut adj_list = Vec::with_capacity(funcs.len());
94 for (_, func) in funcs {
95 if let SpecFunc::Defined { body, .. } = func {
96 let deps = deps(body)
97 .iter()
98 .filter_map(|s| s2i.get(s).copied())
99 .collect_vec();
100 adj_list.push(deps);
101 } else {
102 adj_list.push(vec![]);
103 }
104 }
105 let mut g = IndexGraph::from_adjacency_list(&adj_list);
106 g.transpose();
107
108 match g.toposort_or_scc() {
110 Ok(is) => Ok(is),
111 Err(mut scc) => {
112 let cycle = scc.pop().unwrap();
113 Err(cycle.iter().map(|i| funcs[*i].0).collect())
114 }
115 }
116}
117
118pub fn deps(body: &Binder<Expr>) -> FxIndexSet<FluxDefId> {
120 struct DepsVisitor(FxIndexSet<FluxDefId>);
121 impl TypeVisitor for DepsVisitor {
122 fn visit_expr(&mut self, expr: &Expr) -> ControlFlow<!> {
123 if let ExprKind::App(func, ..) = expr.kind()
124 && let ExprKind::GlobalFunc(SpecFuncKind::Def(did)) = func.kind()
125 {
126 self.0.insert(*did);
127 }
128 expr.super_visit_with(self)
129 }
130 }
131 let mut visitor = DepsVisitor(Default::default());
132 let _ = body.visit_with(&mut visitor);
133 visitor.0
134}