simplicity/types/
incomplete.rs1use crate::dag::{Dag, DagLike, NoSharing};
12use crate::types::union_bound::PointerLike;
13
14use super::context::BoundRefSharing;
15use super::{Bound, BoundRef, Context};
16use super::{MAX_DISPLAY_DEPTH, MAX_DISPLAY_LENGTH};
17
18use std::fmt;
19use std::sync::Arc;
20
21#[derive(Clone)]
23pub enum Incomplete {
24 Free(String),
26 Cycle,
28 Sum(Arc<Incomplete>, Arc<Incomplete>),
30 Product(Arc<Incomplete>, Arc<Incomplete>),
32 Final(Arc<super::Final>),
34}
35
36impl Incomplete {
37 fn into_dag(mut self) -> Dag<Arc<Self>> {
40 use core::{mem, ptr};
41 let ret = match &mut self {
42 Incomplete::Sum(ref mut left, ref mut right)
43 | Incomplete::Product(ref mut left, ref mut right) => {
44 unsafe {
55 let left = ptr::read(left);
60 let right = ptr::read(right);
61 Dag::Binary(left, right)
62 }
63 }
64 Incomplete::Cycle => Dag::Nullary,
65 Incomplete::Free(s) => {
66 unsafe {
69 ptr::read(s);
70 }
71 Dag::Nullary
72 }
73 Incomplete::Final(fin) => {
74 unsafe {
76 ptr::read(fin);
77 }
78 Dag::Nullary
79 }
80 };
81 mem::forget(self);
85 ret
86 }
87}
88
89impl DagLike for &'_ Incomplete {
90 type Node = Incomplete;
91 fn data(&self) -> &Incomplete {
92 self
93 }
94 fn as_dag_node(&self) -> Dag<Self> {
95 match *self {
96 Incomplete::Free(_) | Incomplete::Cycle | Incomplete::Final(_) => Dag::Nullary,
97 Incomplete::Sum(ref left, ref right) | Incomplete::Product(ref left, ref right) => {
98 Dag::Binary(left, right)
99 }
100 }
101 }
102}
103
104impl fmt::Debug for Incomplete {
105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
106 fmt::Display::fmt(self, f)
107 }
108}
109
110impl fmt::Display for Incomplete {
111 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
112 let mut skip_next = false;
113 for data in self.verbose_pre_order_iter::<NoSharing>(Some(MAX_DISPLAY_DEPTH)) {
114 if data.index > MAX_DISPLAY_LENGTH {
115 write!(f, "... [truncated type after {} nodes]", MAX_DISPLAY_LENGTH)?;
116 return Ok(());
117 }
118 if data.depth == MAX_DISPLAY_DEPTH {
119 if data.n_children_yielded == 0 {
120 f.write_str("...")?;
121 }
122 continue;
123 }
124
125 if skip_next {
126 skip_next = false;
127 continue;
128 }
129
130 match (data.node, data.n_children_yielded) {
131 (Incomplete::Free(ref s), _) => f.write_str(s)?,
132 (Incomplete::Cycle, _) => f.write_str("<self-reference>")?,
133 (Incomplete::Sum(ref left, _), 0) if left.is_unit() => {
135 skip_next = true;
136 }
137 (Incomplete::Sum(ref left, _), 1) if left.is_unit() => {}
138 (Incomplete::Sum(ref left, _), 2) if left.is_unit() => {
139 f.write_str("?")?;
140 }
141 (Incomplete::Sum(..), 0) | (Incomplete::Product(..), 0) => {
143 if data.index > 0 {
144 f.write_str("(")?;
145 }
146 }
147 (Incomplete::Sum(..), 2) | (Incomplete::Product(..), 2) => {
148 if data.index > 0 {
149 f.write_str(")")?;
150 }
151 }
152 (Incomplete::Sum(..), _) => f.write_str(" + ")?,
153 (Incomplete::Product(..), _) => f.write_str(" × ")?,
154 (Incomplete::Final(ref fnl), _) => fnl.fmt(f)?,
155 }
156 }
157 Ok(())
158 }
159}
160
161impl Drop for Incomplete {
162 fn drop(&mut self) {
163 fn push_children(stack: &mut Vec<Arc<Incomplete>>, inner: Incomplete) {
165 use crate::dag::Dag;
166 match inner.into_dag() {
167 Dag::Nullary => {}
168 Dag::Unary(child) => stack.push(child),
169 Dag::Binary(left, right) => {
170 stack.push(left);
171 stack.push(right);
172 }
173 }
174 }
175
176 let mut stack = Vec::new();
177 push_children(&mut stack, std::mem::replace(self, Incomplete::Cycle));
178 while let Some(child) = stack.pop() {
179 if let Some(mut child) = Arc::into_inner(child) {
180 push_children(&mut stack, std::mem::replace(&mut child, Incomplete::Cycle));
181 }
182 }
183 }
184}
185
186impl Incomplete {
187 pub fn is_unit(&self) -> bool {
189 if let Incomplete::Final(ref fnl) = self {
190 fnl.is_unit()
191 } else {
192 false
193 }
194 }
195
196 pub(super) fn occurs_check<'brand>(
201 ctx: &Context<'brand>,
202 bound_ref: BoundRef<'brand>,
203 ) -> Option<Arc<Self>> {
204 use std::collections::HashSet;
205
206 use super::context::OccursCheckId;
207
208 enum OccursCheckStack<'brand> {
210 Iterate(BoundRef<'brand>),
211 Complete(OccursCheckId<'brand>),
212 }
213
214 let mut stack = vec![OccursCheckStack::Iterate(bound_ref)];
216 let mut in_progress = HashSet::new();
217 let mut completed = HashSet::new();
218 while let Some(top) = stack.pop() {
219 let bound = match top {
220 OccursCheckStack::Complete(id) => {
221 in_progress.remove(&id);
222 completed.insert(id);
223 continue;
224 }
225 OccursCheckStack::Iterate(b) => b,
226 };
227
228 let id = bound.occurs_check_id();
229 if completed.contains(&id) {
230 continue;
233 }
234 if !in_progress.insert(id) {
235 return Some(Arc::new(Self::Cycle));
237 }
238
239 stack.push(OccursCheckStack::Complete(id));
240 if let Some((_, child)) = (ctx, bound.shallow_clone()).right_child() {
241 stack.push(OccursCheckStack::Iterate(child));
242 }
243 if let Some((_, child)) = (ctx, bound).left_child() {
244 stack.push(OccursCheckStack::Iterate(child));
245 }
246 }
247
248 None
249 }
250
251 pub(super) fn from_bound_ref<'brand>(
252 ctx: &Context<'brand>,
253 bound_ref: BoundRef<'brand>,
254 ) -> Arc<Self> {
255 if let Some(err) = Self::occurs_check(ctx, bound_ref.shallow_clone()) {
256 return err;
257 }
258
259 let mut finalized = vec![];
262 for data in (ctx, bound_ref).post_order_iter::<BoundRefSharing<'_>>() {
263 let bound_get = data.node.0.get(&data.node.1);
264 let final_data = match bound_get {
265 Bound::Free(s) => Incomplete::Free(s),
266 Bound::Complete(ref arc) => Incomplete::Final(Arc::clone(arc)),
267 Bound::Sum(..) => Incomplete::Sum(
268 Arc::clone(&finalized[data.left_index.unwrap()]),
269 Arc::clone(&finalized[data.right_index.unwrap()]),
270 ),
271 Bound::Product(..) => Incomplete::Product(
272 Arc::clone(&finalized[data.left_index.unwrap()]),
273 Arc::clone(&finalized[data.right_index.unwrap()]),
274 ),
275 };
276
277 finalized.push(Arc::new(final_data));
278 }
279 finalized.pop().unwrap()
280 }
281}