1 //! An iterator over the type substructure.
2 //! WARNING: this does not keep track of the region depth.
5 use crate::ty
::subst
::{GenericArg, GenericArgKind}
;
6 use arrayvec
::ArrayVec
;
7 use rustc_data_structures
::fx
::FxHashSet
;
8 use smallvec
::{self, SmallVec}
;
11 /// Small-storage-optimized implementation of a set
12 /// made specifically for walking type tree.
14 /// Stores elements in a small array up to a certain length
15 /// and switches to `HashSet` when that length is exceeded.
17 Array(ArrayVec
<[T
; 8]>),
21 impl<T
: Eq
+ Hash
+ Copy
> MiniSet
<T
> {
22 /// Creates an empty `MiniSet`.
23 pub fn new() -> Self {
24 MiniSet
::Array(ArrayVec
::new())
27 /// Adds a value to the set.
29 /// If the set did not have this value present, true is returned.
31 /// If the set did have this value present, false is returned.
32 pub fn insert(&mut self, elem
: T
) -> bool
{
34 MiniSet
::Array(array
) => {
35 if array
.iter().any(|e
| *e
== elem
) {
38 if array
.try_push(elem
).is_err() {
39 let mut set
: FxHashSet
<T
> = array
.iter().copied().collect();
41 *self = MiniSet
::Set(set
);
46 MiniSet
::Set(set
) => set
.insert(elem
),
51 // The TypeWalker's stack is hot enough that it's worth going to some effort to
52 // avoid heap allocations.
53 type TypeWalkerStack
<'tcx
> = SmallVec
<[GenericArg
<'tcx
>; 8]>;
55 pub struct TypeWalker
<'tcx
> {
56 stack
: TypeWalkerStack
<'tcx
>,
58 visited
: MiniSet
<GenericArg
<'tcx
>>,
61 /// An iterator for walking the type tree.
63 /// It's very easy to produce a deeply
64 /// nested type tree with a lot of
65 /// identical subtrees. In order to work efficiently
66 /// in this situation walker only visits each type once.
67 /// It maintains a set of visited types and
68 /// skips any types that are already there.
69 impl<'tcx
> TypeWalker
<'tcx
> {
70 pub fn new(root
: GenericArg
<'tcx
>) -> Self {
71 Self { stack: smallvec![root], last_subtree: 1, visited: MiniSet::new() }
74 /// Skips the subtree corresponding to the last type
75 /// returned by `next()`.
77 /// Example: Imagine you are walking `Foo<Bar<i32>, usize>`.
80 /// let mut iter: TypeWalker = ...;
81 /// iter.next(); // yields Foo
82 /// iter.next(); // yields Bar<i32>
83 /// iter.skip_current_subtree(); // skips i32
84 /// iter.next(); // yields usize
86 pub fn skip_current_subtree(&mut self) {
87 self.stack
.truncate(self.last_subtree
);
91 impl<'tcx
> Iterator
for TypeWalker
<'tcx
> {
92 type Item
= GenericArg
<'tcx
>;
94 fn next(&mut self) -> Option
<GenericArg
<'tcx
>> {
95 debug
!("next(): stack={:?}", self.stack
);
97 let next
= self.stack
.pop()?
;
98 self.last_subtree
= self.stack
.len();
99 if self.visited
.insert(next
) {
100 push_inner(&mut self.stack
, next
);
101 debug
!("next: stack={:?}", self.stack
);
108 impl GenericArg
<'tcx
> {
109 /// Iterator that walks `self` and any types reachable from
110 /// `self`, in depth-first order. Note that just walks the types
111 /// that appear in `self`, it does not descend into the fields of
112 /// structs or variants. For example:
115 /// isize => { isize }
116 /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
117 /// [isize] => { [isize], isize }
119 pub fn walk(self) -> TypeWalker
<'tcx
> {
120 TypeWalker
::new(self)
123 /// Iterator that walks the immediate children of `self`. Hence
124 /// `Foo<Bar<i32>, u32>` yields the sequence `[Bar<i32>, u32]`
125 /// (but not `i32`, like `walk`).
127 /// Iterator only walks items once.
128 /// It accepts visited set, updates it with all visited types
129 /// and skips any types that are already there.
132 visited
: &mut MiniSet
<GenericArg
<'tcx
>>,
133 ) -> impl Iterator
<Item
= GenericArg
<'tcx
>> {
134 let mut stack
= SmallVec
::new();
135 push_inner(&mut stack
, self);
136 stack
.retain(|a
| visited
.insert(*a
));
141 impl<'tcx
> super::TyS
<'tcx
> {
142 /// Iterator that walks `self` and any types reachable from
143 /// `self`, in depth-first order. Note that just walks the types
144 /// that appear in `self`, it does not descend into the fields of
145 /// structs or variants. For example:
148 /// isize => { isize }
149 /// Foo<Bar<isize>> => { Foo<Bar<isize>>, Bar<isize>, isize }
150 /// [isize] => { [isize], isize }
152 pub fn walk(&'tcx
self) -> TypeWalker
<'tcx
> {
153 TypeWalker
::new(self.into())
157 // We push `GenericArg`s on the stack in reverse order so as to
158 // maintain a pre-order traversal. As of the time of this
159 // writing, the fact that the traversal is pre-order is not
160 // known to be significant to any code, but it seems like the
161 // natural order one would expect (basically, the order of the
162 // types as they are written).
163 fn push_inner
<'tcx
>(stack
: &mut TypeWalkerStack
<'tcx
>, parent
: GenericArg
<'tcx
>) {
164 match parent
.unpack() {
165 GenericArgKind
::Type(parent_ty
) => match parent_ty
.kind
{
176 | ty
::Placeholder(..)
178 | ty
::Foreign(..) => {}
180 ty
::Array(ty
, len
) => {
181 stack
.push(len
.into());
182 stack
.push(ty
.into());
185 stack
.push(ty
.into());
188 stack
.push(mt
.ty
.into());
190 ty
::Ref(lt
, ty
, _
) => {
191 stack
.push(ty
.into());
192 stack
.push(lt
.into());
194 ty
::Projection(data
) => {
195 stack
.extend(data
.substs
.iter().rev());
197 ty
::Dynamic(obj
, lt
) => {
198 stack
.push(lt
.into());
199 stack
.extend(obj
.iter().rev().flat_map(|predicate
| {
200 let (substs
, opt_ty
) = match predicate
.skip_binder() {
201 ty
::ExistentialPredicate
::Trait(tr
) => (tr
.substs
, None
),
202 ty
::ExistentialPredicate
::Projection(p
) => (p
.substs
, Some(p
.ty
)),
203 ty
::ExistentialPredicate
::AutoTrait(_
) =>
206 (ty
::InternalSubsts
::empty(), None
)
210 substs
.iter().rev().chain(opt_ty
.map(|ty
| ty
.into()))
214 | ty
::Opaque(_
, substs
)
215 | ty
::Closure(_
, substs
)
216 | ty
::Generator(_
, substs
, _
)
218 | ty
::FnDef(_
, substs
) => {
219 stack
.extend(substs
.iter().rev());
221 ty
::GeneratorWitness(ts
) => {
222 stack
.extend(ts
.skip_binder().iter().rev().map(|ty
| ty
.into()));
225 stack
.push(sig
.skip_binder().output().into());
226 stack
.extend(sig
.skip_binder().inputs().iter().copied().rev().map(|ty
| ty
.into()));
229 GenericArgKind
::Lifetime(_
) => {}
230 GenericArgKind
::Const(parent_ct
) => {
231 stack
.push(parent_ct
.ty
.into());
232 match parent_ct
.val
{
233 ty
::ConstKind
::Infer(_
)
234 | ty
::ConstKind
::Param(_
)
235 | ty
::ConstKind
::Placeholder(_
)
236 | ty
::ConstKind
::Bound(..)
237 | ty
::ConstKind
::Value(_
)
238 | ty
::ConstKind
::Error(_
) => {}
240 ty
::ConstKind
::Unevaluated(_
, substs
, _
) => {
241 stack
.extend(substs
.iter().rev());