1use std::{any::Any, collections::HashMap};
14
15use crate::ast::*;
16use derive_generic_visitor::*;
17use index_vec::Idx;
18use indexmap::IndexMap;
19
20#[visitable_group(
39 visitor(drive(&VisitAst)),
41 visitor(drive_mut(&mut VisitAstMut)),
42 drive(
44 AbortKind, Assert, BinOp, Body, BorrowKind, BuiltinFunId, BuiltinIndexOp, BuiltinTy, Call,
45 CastKind, ClosureInfo, ClosureKind, ConstantExpr, ConstGenericVar, ConstGenericVarId,
46 Disambiguator, ExistentialPredicate, Field, FieldId, FieldProjKind, FloatTy, FloatValue,
47 FnOperand, FunId, FunIdOrTraitMethodRef, FunSig, ImplElem, IntegerTy, Literal, LiteralTy,
48 llbc_ast::Block, llbc_ast::ExprBody, llbc_ast::RawStatement, llbc_ast::Switch,
49 Locals, Name, NullOp, Opaque, Operand, PathElem, PlaceKind, ProjectionElem, RawConstantExpr,
50 RefKind, RegionId, RegionVar, Rvalue, ScalarValue, TraitClauseId, TraitItemName,
51 TranslatedCrate, TypeDeclKind, TypeId, TypeVar, TypeVarId,
52 ullbc_ast::BlockData, ullbc_ast::BlockId, ullbc_ast::ExprBody, ullbc_ast::RawStatement,
53 ullbc_ast::RawTerminator, ullbc_ast::SwitchTargets, ullbc_ast::Terminator,
54 UnOp, Local, Variant, VariantId, LocalId,
55 for<T: AstVisitable> Box<T>,
56 for<T: AstVisitable> Option<T>,
57 for<A: AstVisitable, B: AstVisitable> (A, B),
58 for<A: AstVisitable, B: AstVisitable> Result<A, B>,
59 for<A: AstVisitable, B: AstVisitable> OutlivesPred<A, B>,
60 for<T: AstVisitable> Vec<T>,
61 for<I: Idx, T: AstVisitable> Vector<I, T>,
62 ),
63 override(
66 DeBruijnId, Ty, TyKind, Region, ConstGeneric, TraitRef, TraitRefKind,
67 FunDeclRef, GlobalDeclRef, TraitDeclRef, TraitImplRef,
68 GenericArgs, GenericParams, TraitClause, TraitTypeConstraint, Place,
69 for<T: AstVisitable + Idx> DeBruijnVar<T>,
70 for<T: AstVisitable> RegionBinder<T>,
71 for<T: AstVisitable> Binder<T>,
72 llbc_statement: llbc_ast::Statement, ullbc_statement: ullbc_ast::Statement,
73 AggregateKind, FnPtr, ItemKind, ItemMeta, Span,
74 FunDeclId, GlobalDeclId, TypeDeclId, TraitDeclId, TraitImplId,
75 FunDecl, GlobalDecl, TypeDecl, TraitDecl, TraitImpl,
76 )
77)]
78pub trait AstVisitable: Any {
79 fn name(&self) -> &'static str {
81 std::any::type_name::<Self>()
82 }
83 fn dyn_visit<T: AstVisitable>(&self, f: impl FnMut(&T)) {
85 let _ = self.drive(&mut DynVisitor::new_shared::<T>(f));
86 }
87 fn dyn_visit_mut<T: AstVisitable>(&mut self, f: impl FnMut(&mut T)) {
89 let _ = self.drive_mut(&mut DynVisitor::new_mut::<T>(f));
90 }
91}
92
93impl<K: Any, T: AstVisitable> AstVisitable for HashMap<K, T> {
95 fn drive<V: VisitAst>(&self, v: &mut V) -> ControlFlow<V::Break> {
96 for x in self.values() {
97 v.visit(x)?;
98 }
99 Continue(())
100 }
101 fn drive_mut<V: VisitAstMut>(&mut self, v: &mut V) -> ControlFlow<V::Break> {
102 for x in self.values_mut() {
103 v.visit(x)?;
104 }
105 Continue(())
106 }
107}
108
109impl<K: Any, T: AstVisitable> AstVisitable for IndexMap<K, T> {
111 fn drive<V: VisitAst>(&self, v: &mut V) -> ControlFlow<V::Break> {
112 for x in self.values() {
113 v.visit(x)?;
114 }
115 Continue(())
116 }
117 fn drive_mut<V: VisitAstMut>(&mut self, v: &mut V) -> ControlFlow<V::Break> {
118 for x in self.values_mut() {
119 v.visit(x)?;
120 }
121 Continue(())
122 }
123}
124
125#[visitable_group(
138 visitor(drive_body(&VisitBody)),
140 visitor(drive_body_mut(&mut VisitBodyMut)),
141 skip(
143 AbortKind, BinOp, BorrowKind, ConstantExpr, ConstGeneric, FieldId, FieldProjKind,
144 FunDeclId, FunIdOrTraitMethodRef, GenericArgs, GlobalDeclRef, IntegerTy, Locals,
145 NullOp, RefKind, ScalarValue, Span, Ty, TypeDeclId, TypeId, UnOp, VariantId, LocalId,
146 ),
147 drive(
149 Assert, PlaceKind,
150 llbc_ast::ExprBody, llbc_ast::RawStatement, llbc_ast::Switch,
151 ullbc_ast::BlockData, ullbc_ast::ExprBody, ullbc_ast::RawStatement,
152 ullbc_ast::RawTerminator, ullbc_ast::SwitchTargets,
153 Body, Opaque,
154 for<T: BodyVisitable> Box<T>,
155 for<T: BodyVisitable> Option<T>,
156 for<T: BodyVisitable, E: BodyVisitable> Result<T, E>,
157 for<A: BodyVisitable, B: BodyVisitable> (A, B),
158 for<T: BodyVisitable> Vec<T>,
159 for<I: Idx, T: BodyVisitable> Vector<I, T>,
160 ),
161 override(
164 AggregateKind, Call, FnOperand, FnPtr,
165 Operand, Place, ProjectionElem, Rvalue,
166 llbc_block: llbc_ast::Block,
167 llbc_statement: llbc_ast::Statement,
168 ullbc_statement: ullbc_ast::Statement,
169 ullbc_terminator: ullbc_ast::Terminator,
170 ullbc_block_id: ullbc_ast::BlockId,
171 )
172)]
173pub trait BodyVisitable: Any {
174 fn dyn_visit_in_body<T: BodyVisitable>(&self, f: impl FnMut(&T)) {
176 let _ = self.drive_body(&mut DynVisitor::new_shared::<T>(f));
177 }
178
179 fn dyn_visit_in_body_mut<T: BodyVisitable>(&mut self, f: impl FnMut(&mut T)) {
181 let _ = self.drive_body_mut(&mut DynVisitor::new_mut::<T>(f));
182 }
183}
184
185#[derive(Visitor)]
188pub struct DynVisitor<F> {
189 enter: F,
190}
191impl DynVisitor<()> {
192 pub fn new_shared<T: Any>(mut f: impl FnMut(&T)) -> DynVisitor<impl FnMut(&dyn Any)> {
193 let enter = move |x: &dyn Any| {
194 if let Some(x) = x.downcast_ref::<T>() {
195 f(x);
196 }
197 };
198 DynVisitor { enter }
199 }
200 pub fn new_mut<T: Any>(mut f: impl FnMut(&mut T)) -> DynVisitor<impl FnMut(&mut dyn Any)> {
201 let enter = move |x: &mut dyn Any| {
202 if let Some(x) = x.downcast_mut::<T>() {
203 f(x);
204 }
205 };
206 DynVisitor { enter }
207 }
208}
209impl<F> VisitAst for DynVisitor<F>
210where
211 F: FnMut(&dyn Any),
212{
213 fn visit<'a, T: AstVisitable>(&'a mut self, x: &T) -> ControlFlow<Self::Break> {
214 (self.enter)(x);
215 x.drive(self)?;
216 Continue(())
217 }
218}
219impl<F> VisitAstMut for DynVisitor<F>
220where
221 F: FnMut(&mut dyn Any),
222{
223 fn visit<'a, T: AstVisitable>(&'a mut self, x: &mut T) -> ControlFlow<Self::Break> {
224 (self.enter)(x);
225 x.drive_mut(self)?;
226 Continue(())
227 }
228}
229impl<F> VisitBody for DynVisitor<F>
230where
231 F: FnMut(&dyn Any),
232{
233 fn visit<'a, T: BodyVisitable>(&'a mut self, x: &T) -> ControlFlow<Self::Break> {
234 (self.enter)(x);
235 x.drive_body(self)?;
236 Continue(())
237 }
238}
239impl<F> VisitBodyMut for DynVisitor<F>
240where
241 F: FnMut(&mut dyn Any),
242{
243 fn visit<'a, T: BodyVisitable>(&'a mut self, x: &mut T) -> ControlFlow<Self::Break> {
244 (self.enter)(x);
245 x.drive_body_mut(self)?;
246 Continue(())
247 }
248}