1 // Copyright (c) Meta Platforms, Inc. and affiliates.
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
7 use crate::reason::Reason;
8 use crate::typing_defs;
10 /// A type which can be traversed by a `Visitor`.
11 pub trait Walkable<R: Reason> {
12 fn accept(&self, v: &mut dyn Visitor<R>) {
15 fn recurse(&self, _v: &mut dyn Visitor<R>) {}
18 /// A visitor over data structures containing decls or types.
19 pub trait Visitor<R: Reason> {
20 /// Must return `self`.
21 fn object(&mut self) -> &mut dyn Visitor<R>;
23 fn visit_decl_ty(&mut self, o: &decl_defs::DeclTy<R>) {
24 o.recurse(self.object());
26 fn visit_ty(&mut self, o: &typing_defs::Ty<R>) {
27 o.recurse(self.object());
31 impl<R: Reason, T: Walkable<R>> Walkable<R> for Option<T> {
32 fn recurse(&self, v: &mut dyn Visitor<R>) {
34 Some(some) => some.accept(v),
40 impl<R: Reason, T: Walkable<R>> Walkable<R> for Box<T> {
41 fn recurse(&self, v: &mut dyn Visitor<R>) {
42 let obj: &T = &**self;
47 impl<R: Reason, T: Walkable<R>> Walkable<R> for [T] {
48 fn recurse(&self, v: &mut dyn Visitor<R>) {
55 impl<R: Reason, T: Walkable<R>> Walkable<R> for Vec<T> {
56 fn recurse(&self, v: &mut dyn Visitor<R>) {
63 impl<R: Reason, K: Walkable<R>, V: Walkable<R>> Walkable<R> for std::collections::BTreeMap<K, V> {
64 fn recurse(&self, v: &mut dyn Visitor<R>) {
65 for (key, val) in self {
72 impl<R: Reason, T: Walkable<R>> Walkable<R> for hcons::Hc<T> {
73 fn recurse(&self, v: &mut dyn Visitor<R>) {
74 let obj: &T = &**self;
79 /// Generate an impl of `Walkable<R>` for the given type which recurses on the
84 /// Suppose we have this struct definition:
86 /// struct Foo<R: Reason> {
89 /// constraint: Ty<R>,
92 /// We can generate an impl of `Walkable<R>` for `Foo<R>` like this:
94 /// walkable!(Foo<R> => [ty, constraint]);
96 /// The macro will expand to something like the following:
98 /// impl<R: Reason> Walkable<R> for Foo<R> {
99 /// fn recurse(&self, v: &mut dyn Visitor<R>) {
100 /// self.ty.accept(v);
101 /// self.constraint.accept(v);
105 /// Note that the macro implicitly introduces the type parameter `R`.
107 /// If the type is one which a `Visitor` may be interested in handling, add a
108 /// `visit_` method to the `Visitor` trait, and reference that method with the
109 /// `as` keyword in the `walkable!` macro:
111 /// walkable!(Foo<R> as visit_foo => [ty, constraint]);
113 /// This will expand to:
115 /// impl<R: Reason> Walkable<R> for Foo<R> {
116 /// fn accept(&self, v: &mut dyn crate::visitor::Visitor<R>) {
117 /// v.visit_foo(self);
119 /// fn recurse(&self, v: &mut dyn Visitor<R>) {
120 /// self.ty.accept(v);
121 /// self.constraint.accept(v);
125 /// If the type has type parameters other than `R`:
127 /// struct Foo<R: Reason, T> {
133 /// Use the `impl` and `for` keywords to introduce all type parameters. Note
134 /// that the `R: Reason` parameter is no longer implicitly introduced:
136 /// walkable!(impl<R: Reason, T> for Foo<R, T> as visit_foo => [ty, constraint]);
140 /// enum Typeconst<R: Reason> {
141 /// Abstract(AbstractTypeconst<R>),
142 /// Concrete(ConcreteTypeconst<R>),
145 /// Write a list of `pattern => [fields]` arms in curly braces:
147 /// walkable!(Typeconst<R> as visit_typeconst => {
148 /// Self::Abstract(at) => [at],
149 /// Self::Concrete(ct) => [ct],
152 /// For leaves (structures which cannot contain the types we are interested in
153 /// visiting), either 1) don't implement `Walkable<R>`, and don't specify fields
154 /// of that type in implementations of `Walkable<R>` for other types (as done
155 /// with the field `pos` in `Foo<R>` in the example above), or 2) use
156 /// `walkable!` to generate a no-op implementation of `Walkable<R>` (when not
157 /// implementing `Walkable<R>` would be inconvenient):
159 /// #[derive(Ord, PartialOrd)]
160 /// enum Kind { A, B, C, D }
161 /// struct Bar<R> { map: BTreeMap<Kind, Ty<R>> }
162 /// walkable!(Bar<R> => [map]); // requires Kind : Walkable<R>
165 /// This leaf-node use expands to:
167 /// impl<R: Reason> Walkable<R> for Kind {}
168 macro_rules! walkable {
169 ( @ACCEPT($r:ident, $visit:ident) ) => {
170 fn accept(& self, v: &mut dyn $crate::visitor::Visitor<$r>) {
174 ( @STRUCT($r:ident, $reason_bound:path, [$($gen:ident)*], $name:ty, $({$accept:item},)? [$($e:tt)*]) ) => {
175 impl<$r: $reason_bound $( , $gen: $crate::visitor::Walkable<$r> )* > $crate::visitor::Walkable<$r> for $name {
178 #[allow(unused_variables)]
179 fn recurse(&self, v: &mut dyn $crate::visitor::Visitor<$r>) {
186 ( @ENUM($r:ident, $reason_bound:path, [$($gen:ident)*], $name:ty, $({$accept:item},)? [$( $variant:pat, [$($e:tt)*] )*]) ) => {
187 impl<$r: $reason_bound $( , $gen: $crate::visitor::Walkable<$r> )* > $crate::visitor::Walkable<$r> for $name {
190 #[allow(unused_variables)]
191 fn recurse(& self, v: &mut dyn $crate::visitor::Visitor<$r>) {
204 ( impl < $r:ident : $bound:path $( , $gen:ident )* $(,)? > for $name:ty as $visit:ident => [ $($e:tt),* $(,)? ] ) => {
205 walkable! { @STRUCT($r, $bound, [$($gen)*], $name, {walkable!{ @ACCEPT($r, $visit) }}, [$($e)*]) }
207 ( impl < $r:ident : $bound:path $( , $gen:ident )* $(,)? > for $name:ty => [ $($e:tt),* $(,)? ] ) => {
208 walkable! { @STRUCT($r, $bound, [$($gen)*], $name, [$($e)*]) }
210 ( impl < $r:ident : $bound:path $( , $gen:ident )* $(,)? > for $name:ty as $visit:ident => { $( $variant:pat => [ $($e:tt),* $(,)? ] ),* $(,)? } ) => {
211 walkable! { @ENUM($r, $crate::reason::Reason, [$($gen)*], $name, {walkable!{ @ACCEPT($r, $visit) }}, [$($variant, [$($e)*])*]) }
213 ( impl < $r:ident : $bound:path $( , $gen:ident )* $(,)? > for $name:ty => { $( $variant:pat => [ $($e:tt),* $(,)? ] ),* $(,)? } ) => {
214 walkable! { @ENUM($r, $crate::reason::Reason, [$($gen)*], $name, [$($variant, [$($e)*])*]) }
216 ( $name:ty as $visit:ident => [ $($e:tt),* $(,)? ] ) => {
217 walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, {walkable!{ @ACCEPT(R, $visit) }}, [$($e)*]) }
219 ( $name:ty => [ $($e:tt),* $(,)? ] ) => {
220 walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, [$($e)*]) }
222 ( $name:ty as $visit:ident => { $( $variant:pat => [ $($e:tt),* $(,)? ] ),* $(,)? } ) => {
223 walkable! { @ENUM(R, $crate::reason::Reason, [], $name, {walkable!{ @ACCEPT(R, $visit) }}, [$($variant, [$($e)*])*]) }
225 ( $name:ty => { $( $variant:pat => [ $($e:tt),* $(,)? ] ),* $(,)? } ) => {
226 walkable! { @ENUM(R, $crate::reason::Reason, [], $name, [$($variant, [$($e)*])*]) }
228 ( $name:ty as $visit:ident) => {
229 walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, {walkable!{ @ACCEPT(R, $visit) }}, []) }
232 walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, []) }
236 walkable!(impl<R: Reason, A, B> for (A, B) => [0, 1]);
237 walkable!(impl<R: Reason, A, B, C> for (A, B, C) => [0, 1, 2]);
238 walkable!(impl<R: Reason, A, B, C, D> for (A, B, C, D) => [0, 1, 2, 3]);