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(debruijn, _) if debruijn < self.outer_index => {
82                        ControlFlow::Continue(())
83                    }
84                    _ => {
85                        if (self.callback)(r) {
86                            ControlFlow::Break(())
87                        } else {
88                            ControlFlow::Continue(())
89                        }
90                    }
91                }
92            }
93
94            fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
95                if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) {
97                    ty.super_visit_with(self)
98                } else {
99                    ControlFlow::Continue(())
100                }
101            }
102        }
103
104        value.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }).is_break()
105    }
106
107    pub fn collect_constrained_late_bound_regions<T>(
112        self,
113        value: Binder<'tcx, T>,
114    ) -> FxIndexSet<ty::BoundRegionKind>
115    where
116        T: TypeFoldable<TyCtxt<'tcx>>,
117    {
118        self.collect_late_bound_regions(value, true)
119    }
120
121    pub fn collect_referenced_late_bound_regions<T>(
123        self,
124        value: Binder<'tcx, T>,
125    ) -> FxIndexSet<ty::BoundRegionKind>
126    where
127        T: TypeFoldable<TyCtxt<'tcx>>,
128    {
129        self.collect_late_bound_regions(value, false)
130    }
131
132    fn collect_late_bound_regions<T>(
133        self,
134        value: Binder<'tcx, T>,
135        just_constrained: bool,
136    ) -> FxIndexSet<ty::BoundRegionKind>
137    where
138        T: TypeFoldable<TyCtxt<'tcx>>,
139    {
140        let mut collector = LateBoundRegionsCollector::new(just_constrained);
141        let value = value.skip_binder();
142        let value = if just_constrained { self.expand_free_alias_tys(value) } else { value };
143        value.visit_with(&mut collector);
144        collector.regions
145    }
146}
147
148struct LateBoundRegionsCollector {
151    current_index: ty::DebruijnIndex,
152    regions: FxIndexSet<ty::BoundRegionKind>,
153
154    just_constrained: bool,
162}
163
164impl LateBoundRegionsCollector {
165    fn new(just_constrained: bool) -> Self {
166        Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
167    }
168}
169
170impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for LateBoundRegionsCollector {
171    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(&mut self, t: &Binder<'tcx, T>) {
172        self.current_index.shift_in(1);
173        t.super_visit_with(self);
174        self.current_index.shift_out(1);
175    }
176
177    fn visit_ty(&mut self, t: Ty<'tcx>) {
178        if self.just_constrained {
179            match t.kind() {
180                ty::Alias(ty::Projection | ty::Inherent | ty::Opaque, _) => {
183                    return;
184                }
185                ty::Alias(ty::Free, _) => bug!("unexpected free alias type"),
187                _ => {}
188            }
189        }
190
191        t.super_visit_with(self)
192    }
193
194    fn visit_const(&mut self, c: ty::Const<'tcx>) {
195        if self.just_constrained {
199            if let ty::ConstKind::Unevaluated(..) = c.kind() {
200                return;
201            }
202        }
203
204        c.super_visit_with(self)
205    }
206
207    fn visit_region(&mut self, r: ty::Region<'tcx>) {
208        if let ty::ReBound(debruijn, br) = r.kind() {
209            if debruijn == self.current_index {
210                self.regions.insert(br.kind);
211            }
212        }
213    }
214}