1use std::ops::ControlFlow;
2
3use rustc_data_structures::fx::FxIndexSet;
4use rustc_type_ir::TypeFoldable;
5
6use crate::ty::{
7 self, Binder, Ty, TyCtxt, TypeFlags, TypeSuperVisitable, TypeVisitable, TypeVisitor,
8};
9
10impl<'tcx> TyCtxt<'tcx> {
14 pub fn for_each_free_region(
16 self,
17 value: &impl TypeVisitable<TyCtxt<'tcx>>,
18 mut callback: impl FnMut(ty::Region<'tcx>),
19 ) {
20 self.any_free_region_meets(value, |r| {
21 callback(r);
22 false
23 });
24 }
25
26 pub fn all_free_regions_meet(
28 self,
29 value: &impl TypeVisitable<TyCtxt<'tcx>>,
30 mut callback: impl FnMut(ty::Region<'tcx>) -> bool,
31 ) -> bool {
32 !self.any_free_region_meets(value, |r| !callback(r))
33 }
34
35 pub fn any_free_region_meets(
37 self,
38 value: &impl TypeVisitable<TyCtxt<'tcx>>,
39 callback: impl FnMut(ty::Region<'tcx>) -> bool,
40 ) -> bool {
41 struct RegionVisitor<F> {
42 outer_index: ty::DebruijnIndex,
60 callback: F,
61 }
62
63 impl<'tcx, F> TypeVisitor<TyCtxt<'tcx>> for RegionVisitor<F>
64 where
65 F: FnMut(ty::Region<'tcx>) -> bool,
66 {
67 type Result = ControlFlow<()>;
68
69 fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
70 &mut self,
71 t: &Binder<'tcx, T>,
72 ) -> Self::Result {
73 self.outer_index.shift_in(1);
74 let result = t.super_visit_with(self);
75 self.outer_index.shift_out(1);
76 result
77 }
78
79 fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
80 match r.kind() {
81 ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), _)
82 if debruijn < self.outer_index =>
83 {
84 ControlFlow::Continue(())
85 }
86 _ => {
87 if (self.callback)(r) {
88 ControlFlow::Break(())
89 } else {
90 ControlFlow::Continue(())
91 }
92 }
93 }
94 }
95
96 fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
97 if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
99 ty.super_visit_with(self)
100 } else {
101 ControlFlow::Continue(())
102 }
103 }
104 }
105
106 value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
107 }
108
109 pub fn collect_constrained_late_bound_regions<T>(
114 self,
115 value: Binder<'tcx, T>,
116 ) -> FxIndexSet<ty::BoundRegionKind>
117 where
118 T: TypeFoldable<TyCtxt<'tcx>>,
119 {
120 self.collect_late_bound_regions(value, true)
121 }
122
123 pub fn collect_referenced_late_bound_regions<T>(
125 self,
126 value: Binder<'tcx, T>,
127 ) -> FxIndexSet<ty::BoundRegionKind>
128 where
129 T: TypeFoldable<TyCtxt<'tcx>>,
130 {
131 self.collect_late_bound_regions(value, false)
132 }
133
134 fn collect_late_bound_regions<T>(
135 self,
136 value: Binder<'tcx, T>,
137 just_constrained: bool,
138 ) -> FxIndexSet<ty::BoundRegionKind>
139 where
140 T: TypeFoldable<TyCtxt<'tcx>>,
141 {
142 let mut collector = LateBoundRegionsCollector::new(just_constrained);
143 let value = value.skip_binder();
144 let value = if just_constrained { self.expand_free_alias_tys(value) } else { value };
145 value.visit_with(&mut collector);
146 collector.regions
147 }
148}
149
150struct LateBoundRegionsCollector {
153 current_index: ty::DebruijnIndex,
154 regions: FxIndexSet<ty::BoundRegionKind>,
155
156 just_constrained: bool,
164}
165
166impl LateBoundRegionsCollector {
167 fn new(just_constrained: bool) -> Self {
168 Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
169 }
170}
171
172impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
173 fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
174 self.current_index.shift_in(1);
175 t.super_visit_with(self);
176 self.current_index.shift_out(1);
177 }
178
179 fn visit_ty(&mut self, t: Ty<'tcx>) {
180 if self.just_constrained {
181 match t.kind() {
182 ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
185 return;
186 }
187 ty::Alias(ty::Free, _) => bug!("unexpected free alias type"),
189 _ => {}
190 }
191 }
192
193 t.super_visit_with(self)
194 }
195
196 fn visit_const(&mut self, c: ty::Const<'tcx>) {
197 if self.just_constrained {
201 if let ty::ConstKind::Unevaluated(..) = c.kind() {
202 return;
203 }
204 }
205
206 c.super_visit_with(self)
207 }
208
209 fn visit_region(&mut self, r: ty::Region<'tcx>) {
210 if let ty::ReBound(ty::BoundVarIndexKind::Bound(debruijn), br) = r.kind() {
211 if debruijn == self.current_index {
212 self.regions.insert(br.kind);
213 }
214 }
215 }
216}