1use std::fmt::Debug;
3use std::ops::ControlFlow;
4
5use crate::{
6 BoundVar, Const, ConstValue, DebruijnIndex, DomainGoal, Goal, InferenceVar, Interner, Lifetime,
7 LifetimeData, PlaceholderIndex, ProgramClause, Ty, TyKind, WhereClause,
8};
9
10mod binder_impls;
11mod boring_impls;
12pub mod visitors;
13
14pub use visitors::VisitExt;
15
16#[macro_export]
20macro_rules! try_break {
21 ($expr:expr) => {
22 match $expr {
23 std::ops::ControlFlow::Continue(c) => c,
24 std::ops::ControlFlow::Break(b) => return std::ops::ControlFlow::Break(b),
25 }
26 };
27}
28
29pub trait TypeVisitor<I: Interner> {
39 type BreakTy;
42
43 fn as_dyn(&mut self) -> &mut dyn TypeVisitor<I, BreakTy = Self::BreakTy>;
51
52 fn visit_ty(&mut self, ty: &Ty<I>, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
57 ty.super_visit_with(self.as_dyn(), outer_binder)
58 }
59
60 fn visit_lifetime(
65 &mut self,
66 lifetime: &Lifetime<I>,
67 outer_binder: DebruijnIndex,
68 ) -> ControlFlow<Self::BreakTy> {
69 lifetime.super_visit_with(self.as_dyn(), outer_binder)
70 }
71
72 fn visit_const(
77 &mut self,
78 constant: &Const<I>,
79 outer_binder: DebruijnIndex,
80 ) -> ControlFlow<Self::BreakTy> {
81 constant.super_visit_with(self.as_dyn(), outer_binder)
82 }
83
84 fn visit_program_clause(
86 &mut self,
87 clause: &ProgramClause<I>,
88 outer_binder: DebruijnIndex,
89 ) -> ControlFlow<Self::BreakTy> {
90 clause.super_visit_with(self.as_dyn(), outer_binder)
91 }
92
93 fn visit_goal(
95 &mut self,
96 goal: &Goal<I>,
97 outer_binder: DebruijnIndex,
98 ) -> ControlFlow<Self::BreakTy> {
99 goal.super_visit_with(self.as_dyn(), outer_binder)
100 }
101
102 fn visit_domain_goal(
104 &mut self,
105 domain_goal: &DomainGoal<I>,
106 outer_binder: DebruijnIndex,
107 ) -> ControlFlow<Self::BreakTy> {
108 domain_goal.super_visit_with(self.as_dyn(), outer_binder)
109 }
110
111 fn forbid_free_vars(&self) -> bool {
115 false
116 }
117
118 fn visit_free_var(
121 &mut self,
122 bound_var: BoundVar,
123 outer_binder: DebruijnIndex,
124 ) -> ControlFlow<Self::BreakTy> {
125 if self.forbid_free_vars() {
126 panic!(
127 "unexpected free variable `{:?}` with outer binder {:?}",
128 bound_var, outer_binder
129 )
130 } else {
131 ControlFlow::Continue(())
132 }
133 }
134
135 fn forbid_free_placeholders(&self) -> bool {
138 false
139 }
140
141 fn visit_free_placeholder(
144 &mut self,
145 universe: PlaceholderIndex,
146 _outer_binder: DebruijnIndex,
147 ) -> ControlFlow<Self::BreakTy> {
148 if self.forbid_free_placeholders() {
149 panic!("unexpected placeholder type `{:?}`", universe)
150 } else {
151 ControlFlow::Continue(())
152 }
153 }
154
155 fn visit_where_clause(
157 &mut self,
158 where_clause: &WhereClause<I>,
159 outer_binder: DebruijnIndex,
160 ) -> ControlFlow<Self::BreakTy> {
161 where_clause.super_visit_with(self.as_dyn(), outer_binder)
162 }
163
164 fn forbid_inference_vars(&self) -> bool {
168 false
169 }
170
171 fn visit_inference_var(
174 &mut self,
175 var: InferenceVar,
176 _outer_binder: DebruijnIndex,
177 ) -> ControlFlow<Self::BreakTy> {
178 if self.forbid_inference_vars() {
179 panic!("unexpected inference type `{:?}`", var)
180 } else {
181 ControlFlow::Continue(())
182 }
183 }
184
185 fn interner(&self) -> I;
187}
188
189pub trait TypeVisitable<I: Interner>: Debug {
192 fn visit_with<B>(
198 &self,
199 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
200 outer_binder: DebruijnIndex,
201 ) -> ControlFlow<B>;
202}
203
204pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
208 fn super_visit_with<B>(
210 &self,
211 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
212 outer_binder: DebruijnIndex,
213 ) -> ControlFlow<B>;
214}
215
216impl<I: Interner> TypeVisitable<I> for Ty<I> {
220 fn visit_with<B>(
221 &self,
222 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
223 outer_binder: DebruijnIndex,
224 ) -> ControlFlow<B> {
225 visitor.visit_ty(self, outer_binder)
226 }
227}
228
229impl<I> TypeSuperVisitable<I> for Ty<I>
231where
232 I: Interner,
233{
234 fn super_visit_with<B>(
235 &self,
236 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
237 outer_binder: DebruijnIndex,
238 ) -> ControlFlow<B> {
239 let interner = visitor.interner();
240 match self.kind(interner) {
241 TyKind::BoundVar(bound_var) => {
242 if bound_var.shifted_out_to(outer_binder).is_some() {
243 visitor.visit_free_var(*bound_var, outer_binder)
244 } else {
245 ControlFlow::Continue(())
246 }
247 }
248 TyKind::Dyn(clauses) => clauses.visit_with(visitor, outer_binder),
249 TyKind::InferenceVar(var, _) => visitor.visit_inference_var(*var, outer_binder),
250 TyKind::Placeholder(ui) => visitor.visit_free_placeholder(*ui, outer_binder),
251 TyKind::Alias(proj) => proj.visit_with(visitor, outer_binder),
252 TyKind::Function(fun) => fun.visit_with(visitor, outer_binder),
253 TyKind::Adt(_id, substitution) => substitution.visit_with(visitor, outer_binder),
254 TyKind::AssociatedType(_assoc_ty, substitution) => {
255 substitution.visit_with(visitor, outer_binder)
256 }
257 TyKind::Scalar(scalar) => scalar.visit_with(visitor, outer_binder),
258 TyKind::Str => ControlFlow::Continue(()),
259 TyKind::Tuple(arity, substitution) => {
260 try_break!(arity.visit_with(visitor, outer_binder));
261 substitution.visit_with(visitor, outer_binder)
262 }
263 TyKind::OpaqueType(opaque_ty, substitution) => {
264 try_break!(opaque_ty.visit_with(visitor, outer_binder));
265 substitution.visit_with(visitor, outer_binder)
266 }
267 TyKind::Slice(substitution) => substitution.visit_with(visitor, outer_binder),
268 TyKind::FnDef(fn_def, substitution) => {
269 try_break!(fn_def.visit_with(visitor, outer_binder));
270 substitution.visit_with(visitor, outer_binder)
271 }
272 TyKind::Ref(mutability, lifetime, ty) => {
273 try_break!(mutability.visit_with(visitor, outer_binder));
274 try_break!(lifetime.visit_with(visitor, outer_binder));
275 ty.visit_with(visitor, outer_binder)
276 }
277 TyKind::Raw(mutability, ty) => {
278 try_break!(mutability.visit_with(visitor, outer_binder));
279 ty.visit_with(visitor, outer_binder)
280 }
281 TyKind::Never => ControlFlow::Continue(()),
282 TyKind::Array(ty, const_) => {
283 try_break!(ty.visit_with(visitor, outer_binder));
284 const_.visit_with(visitor, outer_binder)
285 }
286 TyKind::Closure(id, substitution) => {
287 try_break!(id.visit_with(visitor, outer_binder));
288 substitution.visit_with(visitor, outer_binder)
289 }
290 TyKind::Coroutine(coroutine, substitution) => {
291 try_break!(coroutine.visit_with(visitor, outer_binder));
292 substitution.visit_with(visitor, outer_binder)
293 }
294 TyKind::CoroutineWitness(witness, substitution) => {
295 try_break!(witness.visit_with(visitor, outer_binder));
296 substitution.visit_with(visitor, outer_binder)
297 }
298 TyKind::Foreign(foreign_ty) => foreign_ty.visit_with(visitor, outer_binder),
299 TyKind::Error => ControlFlow::Continue(()),
300 }
301 }
302}
303
304impl<I: Interner> TypeVisitable<I> for Lifetime<I> {
305 fn visit_with<B>(
306 &self,
307 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
308 outer_binder: DebruijnIndex,
309 ) -> ControlFlow<B> {
310 visitor.visit_lifetime(self, outer_binder)
311 }
312}
313
314impl<I: Interner> TypeSuperVisitable<I> for Lifetime<I> {
315 fn super_visit_with<B>(
316 &self,
317 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
318 outer_binder: DebruijnIndex,
319 ) -> ControlFlow<B> {
320 let interner = visitor.interner();
321 match self.data(interner) {
322 LifetimeData::BoundVar(bound_var) => {
323 if bound_var.shifted_out_to(outer_binder).is_some() {
324 visitor.visit_free_var(*bound_var, outer_binder)
325 } else {
326 ControlFlow::Continue(())
327 }
328 }
329 LifetimeData::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder),
330 LifetimeData::Placeholder(universe) => {
331 visitor.visit_free_placeholder(*universe, outer_binder)
332 }
333 LifetimeData::Static | LifetimeData::Erased | LifetimeData::Error => {
334 ControlFlow::Continue(())
335 }
336 LifetimeData::Phantom(void, ..) => match *void {},
337 }
338 }
339}
340
341impl<I: Interner> TypeVisitable<I> for Const<I> {
342 fn visit_with<B>(
343 &self,
344 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
345 outer_binder: DebruijnIndex,
346 ) -> ControlFlow<B> {
347 visitor.visit_const(self, outer_binder)
348 }
349}
350
351impl<I: Interner> TypeSuperVisitable<I> for Const<I> {
352 fn super_visit_with<B>(
353 &self,
354 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
355 outer_binder: DebruijnIndex,
356 ) -> ControlFlow<B> {
357 let interner = visitor.interner();
358 match &self.data(interner).value {
359 ConstValue::BoundVar(bound_var) => {
360 if bound_var.shifted_out_to(outer_binder).is_some() {
361 visitor.visit_free_var(*bound_var, outer_binder)
362 } else {
363 ControlFlow::Continue(())
364 }
365 }
366 ConstValue::InferenceVar(var) => visitor.visit_inference_var(*var, outer_binder),
367 ConstValue::Placeholder(universe) => {
368 visitor.visit_free_placeholder(*universe, outer_binder)
369 }
370 ConstValue::Concrete(_) => ControlFlow::Continue(()),
371 }
372 }
373}
374
375impl<I: Interner> TypeVisitable<I> for Goal<I> {
376 fn visit_with<B>(
377 &self,
378 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
379 outer_binder: DebruijnIndex,
380 ) -> ControlFlow<B> {
381 visitor.visit_goal(self, outer_binder)
382 }
383}
384
385impl<I: Interner> TypeSuperVisitable<I> for Goal<I> {
386 fn super_visit_with<B>(
387 &self,
388 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
389 outer_binder: DebruijnIndex,
390 ) -> ControlFlow<B> {
391 let interner = visitor.interner();
392 self.data(interner).visit_with(visitor, outer_binder)
393 }
394}
395
396impl<I: Interner> TypeVisitable<I> for ProgramClause<I> {
397 fn visit_with<B>(
398 &self,
399 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
400 outer_binder: DebruijnIndex,
401 ) -> ControlFlow<B> {
402 visitor.visit_program_clause(self, outer_binder)
403 }
404}
405
406impl<I: Interner> TypeVisitable<I> for WhereClause<I> {
407 fn visit_with<B>(
408 &self,
409 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
410 outer_binder: DebruijnIndex,
411 ) -> ControlFlow<B> {
412 visitor.visit_where_clause(self, outer_binder)
413 }
414}
415
416impl<I: Interner> TypeVisitable<I> for DomainGoal<I> {
417 fn visit_with<B>(
418 &self,
419 visitor: &mut dyn TypeVisitor<I, BreakTy = B>,
420 outer_binder: DebruijnIndex,
421 ) -> ControlFlow<B> {
422 visitor.visit_domain_goal(self, outer_binder)
423 }
424}