Merge Typing_logic.Coerce and Typing_logic.IsSubtype
[hiphop-php.git] / hphp / hack / src / rupro / ty / lib / visitor.rs
blobcc12ad7af3aecbdd0b7c9f0938ba291ef4ede9bf
1 // Copyright (c) Meta Platforms, Inc. and affiliates.
2 //
3 // This source code is licensed under the MIT license found in the
4 // LICENSE file in the "hack" directory of this source tree.
6 use crate::decl_defs;
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>) {
13         self.recurse(v);
14     }
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());
25     }
26     fn visit_ty(&mut self, o: &typing_defs::Ty<R>) {
27         o.recurse(self.object());
28     }
31 impl<R: Reason, T: Walkable<R>> Walkable<R> for Option<T> {
32     fn recurse(&self, v: &mut dyn Visitor<R>) {
33         match self {
34             Some(some) => some.accept(v),
35             None => {}
36         }
37     }
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;
43         obj.accept(v)
44     }
47 impl<R: Reason, T: Walkable<R>> Walkable<R> for [T] {
48     fn recurse(&self, v: &mut dyn Visitor<R>) {
49         for obj in self {
50             obj.accept(v);
51         }
52     }
55 impl<R: Reason, T: Walkable<R>> Walkable<R> for Vec<T> {
56     fn recurse(&self, v: &mut dyn Visitor<R>) {
57         for obj in self {
58             obj.accept(v);
59         }
60     }
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 {
66             key.accept(v);
67             val.accept(v);
68         }
69     }
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;
75         obj.accept(v)
76     }
79 /// Generate an impl of `Walkable<R>` for the given type which recurses on the
80 /// given fields.
81 ///
82 /// # Examples
83 ///
84 /// Suppose we have this struct definition:
85 ///
86 ///     struct Foo<R: Reason> {
87 ///         pos: R::Pos,
88 ///         ty: Ty<R>,
89 ///         constraint: Ty<R>,
90 ///     }
91 ///
92 /// We can generate an impl of `Walkable<R>` for `Foo<R>` like this:
93 ///
94 ///     walkable!(Foo<R> => [ty, constraint]);
95 ///
96 /// The macro will expand to something like the following:
97 ///
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);
102 ///         }
103 ///     }
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);
118 ///         }
119 ///         fn recurse(&self, v: &mut dyn Visitor<R>) {
120 ///             self.ty.accept(v);
121 ///             self.constraint.accept(v);
122 ///         }
123 ///     }
125 /// If the type has type parameters other than `R`:
127 ///     struct Foo<R: Reason, T> {
128 ///         pos: R::Pos,
129 ///         ty: T,
130 ///         constraint: T,
131 ///     }
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]);
138 /// For enums:
140 ///     enum Typeconst<R: Reason> {
141 ///         Abstract(AbstractTypeconst<R>),
142 ///         Concrete(ConcreteTypeconst<R>),
143 ///     }
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],
150 ///     });
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>
163 ///     walkable!(Kind);
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>) {
171             v.$visit(self);
172         }
173     };
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 {
176             $($accept)*
178             #[allow(unused_variables)]
179             fn recurse(&self, v: &mut dyn $crate::visitor::Visitor<$r>) {
180                 $(
181                     self.$e.accept(v);
182                 )*
183             }
184         }
185     };
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 {
188             $($accept)*
190             #[allow(unused_variables)]
191             fn recurse(& self, v: &mut dyn $crate::visitor::Visitor<$r>) {
192                 match self {
193                     $(
194                         $variant => {
195                             $(
196                                 $e.accept(v);
197                             )*
198                         }
199                     )*
200                 }
201             }
202         }
203     };
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)*]) }
206     };
207     ( impl < $r:ident : $bound:path $( , $gen:ident )* $(,)? > for $name:ty => [ $($e:tt),* $(,)? ] ) => {
208         walkable! { @STRUCT($r, $bound, [$($gen)*], $name, [$($e)*]) }
209     };
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)*])*]) }
212     };
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)*])*]) }
215     };
216     ( $name:ty as $visit:ident => [ $($e:tt),* $(,)? ] ) => {
217         walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, {walkable!{ @ACCEPT(R, $visit) }}, [$($e)*]) }
218     };
219     ( $name:ty => [ $($e:tt),* $(,)? ] ) => {
220         walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, [$($e)*]) }
221     };
222     ( $name:ty as $visit:ident => { $( $variant:pat => [ $($e:tt),* $(,)? ] ),* $(,)? } ) => {
223         walkable! { @ENUM(R, $crate::reason::Reason, [], $name, {walkable!{ @ACCEPT(R, $visit) }}, [$($variant, [$($e)*])*]) }
224     };
225     ( $name:ty => { $( $variant:pat => [ $($e:tt),* $(,)? ] ),* $(,)? } ) => {
226         walkable! { @ENUM(R, $crate::reason::Reason, [], $name, [$($variant, [$($e)*])*]) }
227     };
228     ( $name:ty as $visit:ident) => {
229         walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, {walkable!{ @ACCEPT(R, $visit) }}, []) }
230     };
231     ( $name:ty ) => {
232         walkable! { @STRUCT(R, $crate::reason::Reason, [], $name, []) }
233     };
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]);