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