1use std::ops::ControlFlow;
2
3use rustc_data_structures::fx::FxIndexSet;
4use rustc_type_ir::fold::TypeFoldable;
5pub use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
6
7use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
8
9impl<'tcx> TyCtxt<'tcx> {
13 pub fn for_each_free_region(
15 self,
16 value: &impl TypeVisitable<TyCtxt<'tcx>>,
17 mut callback: impl FnMut(ty::Region<'tcx>),
18 ) {
19 self.any_free_region_meets(value, |r| {
20 callback(r);
21 false
22 });
23 }
24
25 pub fn all_free_regions_meet(
27 self,
28 value: &impl TypeVisitable<TyCtxt<'tcx>>,
29 mut callback: impl FnMut(ty::Region<'tcx>) -> bool,
30 ) -> bool {
31 !self.any_free_region_meets(value, |r| !callback(r))
32 }
33
34 pub fn any_free_region_meets(
36 self,
37 value: &impl TypeVisitable<TyCtxt<'tcx>>,
38 callback: impl FnMut(ty::Region<'tcx>) -> bool,
39 ) -> bool {
40 struct RegionVisitor<F> {
41 outer_index: ty::DebruijnIndex,
59 callback: F,
60 }
61
62 impl<'tcx, F> TypeVisitor<TyCtxt<'tcx>> for RegionVisitor<F>
63 where
64 F: FnMut(ty::Region<'tcx>) -> bool,
65 {
66 type Result = ControlFlow<()>;
67
68 fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
69 &mut self,
70 t: &Binder<'tcx, T>,
71 ) -> Self::Result {
72 self.outer_index.shift_in(1);
73 let result = t.super_visit_with(self);
74 self.outer_index.shift_out(1);
75 result
76 }
77
78 fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
79 match *r {
80 ty::ReBound(debruijn, _) if debruijn < self.outer_index => {
81 ControlFlow::Continue(())
82 }
83 _ => {
84 if (self.callback)(r) {
85 ControlFlow::Break(())
86 } else {
87 ControlFlow::Continue(())
88 }
89 }
90 }
91 }
92
93 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
94 if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
96 ty.super_visit_with(self)
97 } else {
98 ControlFlow::Continue(())
99 }
100 }
101 }
102
103 value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
104 }
105
106 pub fn collect_constrained_late_bound_regions<T>(
111 self,
112 value: Binder<'tcx, T>,
113 ) -> FxIndexSet<ty::BoundRegionKind>
114 where
115 T: TypeFoldable<TyCtxt<'tcx>>,
116 {
117 self.collect_late_bound_regions(value, true)
118 }
119
120 pub fn collect_referenced_late_bound_regions<T>(
122 self,
123 value: Binder<'tcx, T>,
124 ) -> FxIndexSet<ty::BoundRegionKind>
125 where
126 T: TypeFoldable<TyCtxt<'tcx>>,
127 {
128 self.collect_late_bound_regions(value, false)
129 }
130
131 fn collect_late_bound_regions<T>(
132 self,
133 value: Binder<'tcx, T>,
134 just_constrained: bool,
135 ) -> FxIndexSet<ty::BoundRegionKind>
136 where
137 T: TypeFoldable<TyCtxt<'tcx>>,
138 {
139 let mut collector = LateBoundRegionsCollector::new(just_constrained);
140 let value = value.skip_binder();
141 let value = if just_constrained { self.expand_weak_alias_tys(value) } else { value };
142 value.visit_with(&mut collector);
143 collector.regions
144 }
145}
146
147struct LateBoundRegionsCollector {
150 current_index: ty::DebruijnIndex,
151 regions: FxIndexSet<ty::BoundRegionKind>,
152
153 just_constrained: bool,
161}
162
163impl LateBoundRegionsCollector {
164 fn new(just_constrained: bool) -> Self {
165 Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
166 }
167}
168
169impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
170 fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
171 self.current_index.shift_in(1);
172 t.super_visit_with(self);
173 self.current_index.shift_out(1);
174 }
175
176 fn visit_ty(&mut self, t: Ty<'tcx>) {
177 if self.just_constrained {
178 match t.kind() {
179 ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
182 return;
183 }
184 ty::Alias(ty::Weak, _) => bug!("unexpected weak alias type"),
186 _ => {}
187 }
188 }
189
190 t.super_visit_with(self)
191 }
192
193 fn visit_const(&mut self, c: ty::Const<'tcx>) {
194 if self.just_constrained {
198 if let ty::ConstKind::Unevaluated(..) = c.kind() {
199 return;
200 }
201 }
202
203 c.super_visit_with(self)
204 }
205
206 fn visit_region(&mut self, r: ty::Region<'tcx>) {
207 if let ty::ReBound(debruijn, br) = *r {
208 if debruijn == self.current_index {
209 self.regions.insert(br.kind);
210 }
211 }
212 }
213}
214
215pub struct MaxUniverse {
217 max_universe: ty::UniverseIndex,
218}
219
220impl MaxUniverse {
221 pub fn new() -> Self {
222 MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
223 }
224
225 pub fn max_universe(self) -> ty::UniverseIndex {
226 self.max_universe
227 }
228}
229
230impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for MaxUniverse {
231 fn visit_ty(&mut self, t: Ty<'tcx>) {
232 if let ty::Placeholder(placeholder) = t.kind() {
233 self.max_universe = ty::UniverseIndex::from_u32(
234 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
235 );
236 }
237
238 t.super_visit_with(self)
239 }
240
241 fn visit_const(&mut self, c: ty::consts::Const<'tcx>) {
242 if let ty::ConstKind::Placeholder(placeholder) = c.kind() {
243 self.max_universe = ty::UniverseIndex::from_u32(
244 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
245 );
246 }
247
248 c.super_visit_with(self)
249 }
250
251 fn visit_region(&mut self, r: ty::Region<'tcx>) {
252 if let ty::RePlaceholder(placeholder) = *r {
253 self.max_universe = ty::UniverseIndex::from_u32(
254 self.max_universe.as_u32().max(placeholder.universe.as_u32()),
255 );
256 }
257 }
258}