bend/fun/transform/
definition_pruning.rs1use crate::{
2 diagnostics::WarningType,
3 fun::{Book, Ctx, Name, SourceKind, Term},
4 maybe_grow,
5};
6use hvm::ast::{Net, Tree};
7use std::collections::{hash_map::Entry, HashMap};
8
9#[derive(Clone, Copy, Debug, PartialEq)]
10enum Used {
11 Main,
13 NonBuiltin,
15 Ctr,
17}
18
19type Definitions = HashMap<Name, Used>;
20
21impl Ctx<'_> {
22 pub fn prune(&mut self, prune_all: bool) {
27 let mut used = Definitions::new();
28
29 if let Some(main) = &self.book.entrypoint {
31 let def = self.book.defs.get(main).unwrap();
32 used.insert(main.clone(), Used::Main);
33 for rule in def.rules.iter() {
34 self.book.find_used_definitions_from_term(&rule.body, Used::Main, &mut used);
35 }
36 }
37
38 for def in self.book.defs.values() {
40 if !def.is_builtin() && !(used.get(&def.name) == Some(&Used::Main)) {
41 if self.book.ctrs.contains_key(&def.name) {
42 used.insert(def.name.clone(), Used::Ctr);
43 } else {
44 used.insert(def.name.clone(), Used::NonBuiltin);
45 }
46 for rule in def.rules.iter() {
47 self.book.find_used_definitions_from_term(&rule.body, Used::NonBuiltin, &mut used);
48 }
49 }
50 }
51 for def in self.book.hvm_defs.values() {
52 if !def.source.is_builtin() && !(used.get(&def.name) == Some(&Used::Main)) {
53 used.insert(def.name.clone(), Used::NonBuiltin);
54 self.book.find_used_definitions_from_hvm_net(&def.body, Used::NonBuiltin, &mut used);
55 }
56 }
57
58 fn rm_def(book: &mut Book, def_name: &Name) {
59 if book.defs.contains_key(def_name) {
60 book.defs.shift_remove(def_name);
61 } else if book.hvm_defs.contains_key(def_name) {
62 book.hvm_defs.shift_remove(def_name);
63 } else {
64 unreachable!()
65 }
66 }
67
68 let defs = self.book.defs.iter().map(|(nam, def)| (nam.clone(), def.source.clone()));
70 let hvm_defs = self.book.hvm_defs.iter().map(|(nam, def)| (nam.clone(), def.source.clone()));
71 let names = defs.chain(hvm_defs).collect::<Vec<_>>();
72
73 for (def, src) in names {
74 if let Some(use_) = used.get(&def) {
75 match use_ {
76 Used::Main => {
77 }
79 Used::NonBuiltin => {
80 if prune_all {
83 rm_def(self.book, &def);
84 } else if !def.is_generated() && !matches!(src.kind, SourceKind::Generated) {
85 self.info.add_function_warning(
86 "Definition is unused.",
87 WarningType::UnusedDefinition,
88 def,
89 src,
90 );
91 }
92 }
93 Used::Ctr => {
94 if prune_all {
97 rm_def(self.book, &def);
98 } else {
99 }
101 }
102 }
103 } else {
104 rm_def(self.book, &def);
106 }
107 }
108 }
109}
110
111impl Book {
112 fn find_used_definitions_from_term(&self, term: &Term, used: Used, uses: &mut Definitions) {
114 maybe_grow(|| {
115 let mut to_find = vec![term];
116
117 while let Some(term) = to_find.pop() {
118 match term {
119 Term::Ref { nam: def_name } => self.insert_used(def_name, used, uses),
120 Term::List { .. } => {
121 self.insert_used(&Name::new(crate::fun::builtins::LCONS), used, uses);
122 self.insert_used(&Name::new(crate::fun::builtins::LNIL), used, uses);
123 }
124 Term::Str { .. } => {
125 self.insert_used(&Name::new(crate::fun::builtins::SCONS), used, uses);
126 self.insert_used(&Name::new(crate::fun::builtins::SNIL), used, uses);
127 }
128 _ => {}
129 }
130
131 for child in term.children() {
132 to_find.push(child);
133 }
134 }
135 })
136 }
137
138 fn find_used_definitions_from_hvm_net(&self, net: &Net, used: Used, uses: &mut Definitions) {
139 maybe_grow(|| {
140 let mut to_find = [&net.root]
141 .into_iter()
142 .chain(net.rbag.iter().flat_map(|(_, lft, rgt)| [lft, rgt]))
143 .collect::<Vec<_>>();
144
145 while let Some(term) = to_find.pop() {
146 match term {
147 Tree::Ref { nam } => self.insert_used(&Name::new(nam), used, uses),
148 Tree::Con { fst, snd }
149 | Tree::Dup { fst, snd }
150 | Tree::Opr { fst, snd }
151 | Tree::Swi { fst, snd } => {
152 to_find.push(fst);
153 to_find.push(snd);
154 }
155 Tree::Era | Tree::Var { .. } | Tree::Num { .. } => {}
156 }
157 }
158 })
159 }
160
161 fn insert_used(&self, def_name: &Name, used: Used, uses: &mut Definitions) {
162 if let Entry::Vacant(e) = uses.entry(def_name.clone()) {
163 e.insert(used);
164
165 if let Some(def) = self.defs.get(def_name) {
169 for rule in &def.rules {
170 self.find_used_definitions_from_term(&rule.body, used, uses);
171 }
172 } else if let Some(def) = self.hvm_defs.get(def_name) {
173 self.find_used_definitions_from_hvm_net(&def.body, used, uses);
174 } else {
175 unreachable!()
176 }
177 }
178 }
179}