1 use crate::ty
::{self, Binder, Ty, TyCtxt, TypeFlags}
;
3 use rustc_data_structures
::fx
::FxHashSet
;
4 use rustc_data_structures
::sso
::SsoHashSet
;
5 use rustc_type_ir
::fold
::TypeFoldable
;
6 use std
::ops
::ControlFlow
;
8 pub use rustc_type_ir
::visit
::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}
;
10 ///////////////////////////////////////////////////////////////////////////
13 impl<'tcx
> TyCtxt
<'tcx
> {
14 /// Invoke `callback` on every region appearing free in `value`.
15 pub fn for_each_free_region(
17 value
: &impl TypeVisitable
<TyCtxt
<'tcx
>>,
18 mut callback
: impl FnMut(ty
::Region
<'tcx
>),
20 self.any_free_region_meets(value
, |r
| {
26 /// Returns `true` if `callback` returns true for every region appearing free in `value`.
27 pub fn all_free_regions_meet(
29 value
: &impl TypeVisitable
<TyCtxt
<'tcx
>>,
30 mut callback
: impl FnMut(ty
::Region
<'tcx
>) -> bool
,
32 !self.any_free_region_meets(value
, |r
| !callback(r
))
35 /// Returns `true` if `callback` returns true for some region appearing free in `value`.
36 pub fn any_free_region_meets(
38 value
: &impl TypeVisitable
<TyCtxt
<'tcx
>>,
39 callback
: impl FnMut(ty
::Region
<'tcx
>) -> bool
,
41 struct RegionVisitor
<F
> {
42 /// The index of a binder *just outside* the things we have
43 /// traversed. If we encounter a bound region bound by this
44 /// binder or one outer to it, it appears free. Example:
46 /// ```ignore (illustrative)
47 /// for<'a> fn(for<'b> fn(), T)
49 /// // | | | | here, would be shifted in 1
50 /// // | | | here, would be shifted in 2
51 /// // | | here, would be `INNERMOST` shifted in by 1
52 /// // | here, initially, binder would be `INNERMOST`
55 /// You see that, initially, *any* bound value is free,
56 /// because we've not traversed any binders. As we pass
57 /// through a binder, we shift the `outer_index` by 1 to
58 /// account for the new binder that encloses us.
59 outer_index
: ty
::DebruijnIndex
,
63 impl<'tcx
, F
> TypeVisitor
<TyCtxt
<'tcx
>> for RegionVisitor
<F
>
65 F
: FnMut(ty
::Region
<'tcx
>) -> bool
,
67 type Result
= ControlFlow
<()>;
69 fn visit_binder
<T
: TypeVisitable
<TyCtxt
<'tcx
>>>(
73 self.outer_index
.shift_in(1);
74 let result
= t
.super_visit_with(self);
75 self.outer_index
.shift_out(1);
79 fn visit_region(&mut self, r
: ty
::Region
<'tcx
>) -> Self::Result
{
81 ty
::ReBound(debruijn
, _
) if debruijn
< self.outer_index
=> {
82 ControlFlow
::Continue(())
85 if (self.callback
)(r
) {
86 ControlFlow
::Break(())
88 ControlFlow
::Continue(())
94 fn visit_ty(&mut self, ty
: Ty
<'tcx
>) -> Self::Result
{
95 // We're only interested in types involving regions
96 if ty
.flags().intersects(TypeFlags
::HAS_FREE_REGIONS
) {
97 ty
.super_visit_with(self)
99 ControlFlow
::Continue(())
104 value
.visit_with(&mut RegionVisitor { outer_index: ty::INNERMOST, callback }
).is_break()
107 /// Returns a set of all late-bound regions that are constrained
108 /// by `value`, meaning that if we instantiate those LBR with
109 /// variables and equate `value` with something else, those
110 /// variables will also be equated.
111 pub fn collect_constrained_late_bound_regions
<T
>(
113 value
: Binder
<'tcx
, T
>,
114 ) -> FxHashSet
<ty
::BoundRegionKind
>
116 T
: TypeFoldable
<TyCtxt
<'tcx
>>,
118 self.collect_late_bound_regions(value
, true)
121 /// Returns a set of all late-bound regions that appear in `value` anywhere.
122 pub fn collect_referenced_late_bound_regions
<T
>(
124 value
: Binder
<'tcx
, T
>,
125 ) -> FxHashSet
<ty
::BoundRegionKind
>
127 T
: TypeFoldable
<TyCtxt
<'tcx
>>,
129 self.collect_late_bound_regions(value
, false)
132 fn collect_late_bound_regions
<T
>(
134 value
: Binder
<'tcx
, T
>,
135 just_constrained
: bool
,
136 ) -> FxHashSet
<ty
::BoundRegionKind
>
138 T
: TypeFoldable
<TyCtxt
<'tcx
>>,
140 let mut collector
= LateBoundRegionsCollector
::new(just_constrained
);
141 let value
= value
.skip_binder();
142 let value
= if just_constrained { self.expand_weak_alias_tys(value) }
else { value }
;
143 value
.visit_with(&mut collector
);
148 pub struct ValidateBoundVars
<'tcx
> {
149 bound_vars
: &'tcx ty
::List
<ty
::BoundVariableKind
>,
150 binder_index
: ty
::DebruijnIndex
,
151 // We may encounter the same variable at different levels of binding, so
152 // this can't just be `Ty`
153 visited
: SsoHashSet
<(ty
::DebruijnIndex
, Ty
<'tcx
>)>,
156 impl<'tcx
> ValidateBoundVars
<'tcx
> {
157 pub fn new(bound_vars
: &'tcx ty
::List
<ty
::BoundVariableKind
>) -> Self {
160 binder_index
: ty
::INNERMOST
,
161 visited
: SsoHashSet
::default(),
166 impl<'tcx
> TypeVisitor
<TyCtxt
<'tcx
>> for ValidateBoundVars
<'tcx
> {
167 type Result
= ControlFlow
<()>;
169 fn visit_binder
<T
: TypeVisitable
<TyCtxt
<'tcx
>>>(
173 self.binder_index
.shift_in(1);
174 let result
= t
.super_visit_with(self);
175 self.binder_index
.shift_out(1);
179 fn visit_ty(&mut self, t
: Ty
<'tcx
>) -> Self::Result
{
180 if t
.outer_exclusive_binder() < self.binder_index
181 || !self.visited
.insert((self.binder_index
, t
))
183 return ControlFlow
::Break(());
186 ty
::Bound(debruijn
, bound_ty
) if debruijn
== self.binder_index
=> {
187 if self.bound_vars
.len() <= bound_ty
.var
.as_usize() {
188 bug
!("Not enough bound vars: {:?} not found in {:?}", t
, self.bound_vars
);
190 let list_var
= self.bound_vars
[bound_ty
.var
.as_usize()];
192 ty
::BoundVariableKind
::Ty(kind
) => {
193 if kind
!= bound_ty
.kind
{
195 "Mismatched type kinds: {:?} doesn't var in list {:?}",
202 bug
!("Mismatched bound variable kinds! Expected type, found {:?}", list_var
)
210 t
.super_visit_with(self)
213 fn visit_region(&mut self, r
: ty
::Region
<'tcx
>) -> Self::Result
{
215 ty
::ReBound(index
, br
) if index
== self.binder_index
=> {
216 if self.bound_vars
.len() <= br
.var
.as_usize() {
217 bug
!("Not enough bound vars: {:?} not found in {:?}", br
, self.bound_vars
);
219 let list_var
= self.bound_vars
[br
.var
.as_usize()];
221 ty
::BoundVariableKind
::Region(kind
) => {
224 "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
232 "Mismatched bound variable kinds! Expected region, found {:?}",
241 ControlFlow
::Continue(())
245 /// Collects all the late-bound regions at the innermost binding level
247 struct LateBoundRegionsCollector
{
248 current_index
: ty
::DebruijnIndex
,
249 regions
: FxHashSet
<ty
::BoundRegionKind
>,
251 /// `true` if we only want regions that are known to be
252 /// "constrained" when you equate this type with another type. In
253 /// particular, if you have e.g., `&'a u32` and `&'b u32`, equating
254 /// them constraints `'a == 'b`. But if you have `<&'a u32 as
255 /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those
256 /// types may mean that `'a` and `'b` don't appear in the results,
257 /// so they are not considered *constrained*.
258 just_constrained
: bool
,
261 impl LateBoundRegionsCollector
{
262 fn new(just_constrained
: bool
) -> Self {
263 Self { current_index: ty::INNERMOST, regions: Default::default(), just_constrained }
267 impl<'tcx
> TypeVisitor
<TyCtxt
<'tcx
>> for LateBoundRegionsCollector
{
268 fn visit_binder
<T
: TypeVisitable
<TyCtxt
<'tcx
>>>(&mut self, t
: &Binder
<'tcx
, T
>) {
269 self.current_index
.shift_in(1);
270 t
.super_visit_with(self);
271 self.current_index
.shift_out(1);
274 fn visit_ty(&mut self, t
: Ty
<'tcx
>) {
275 if self.just_constrained
{
277 // If we are only looking for "constrained" regions, we have to ignore the
278 // inputs to a projection as they may not appear in the normalized form.
279 ty
::Alias(ty
::Projection
| ty
::Inherent
| ty
::Opaque
, _
) => {
282 // All weak alias types should've been expanded beforehand.
283 ty
::Alias(ty
::Weak
, _
) => bug
!("unexpected weak alias type"),
288 t
.super_visit_with(self)
291 fn visit_const(&mut self, c
: ty
::Const
<'tcx
>) {
292 // if we are only looking for "constrained" region, we have to
293 // ignore the inputs of an unevaluated const, as they may not appear
294 // in the normalized form
295 if self.just_constrained
{
296 if let ty
::ConstKind
::Unevaluated(..) = c
.kind() {
301 c
.super_visit_with(self)
304 fn visit_region(&mut self, r
: ty
::Region
<'tcx
>) {
305 if let ty
::ReBound(debruijn
, br
) = *r
{
306 if debruijn
== self.current_index
{
307 self.regions
.insert(br
.kind
);
313 /// Finds the max universe present
314 pub struct MaxUniverse
{
315 max_universe
: ty
::UniverseIndex
,
319 pub fn new() -> Self {
320 MaxUniverse { max_universe: ty::UniverseIndex::ROOT }
323 pub fn max_universe(self) -> ty
::UniverseIndex
{
328 impl<'tcx
> TypeVisitor
<TyCtxt
<'tcx
>> for MaxUniverse
{
329 fn visit_ty(&mut self, t
: Ty
<'tcx
>) {
330 if let ty
::Placeholder(placeholder
) = t
.kind() {
331 self.max_universe
= ty
::UniverseIndex
::from_u32(
332 self.max_universe
.as_u32().max(placeholder
.universe
.as_u32()),
336 t
.super_visit_with(self)
339 fn visit_const(&mut self, c
: ty
::consts
::Const
<'tcx
>) {
340 if let ty
::ConstKind
::Placeholder(placeholder
) = c
.kind() {
341 self.max_universe
= ty
::UniverseIndex
::from_u32(
342 self.max_universe
.as_u32().max(placeholder
.universe
.as_u32()),
346 c
.super_visit_with(self)
349 fn visit_region(&mut self, r
: ty
::Region
<'tcx
>) {
350 if let ty
::RePlaceholder(placeholder
) = *r
{
351 self.max_universe
= ty
::UniverseIndex
::from_u32(
352 self.max_universe
.as_u32().max(placeholder
.universe
.as_u32()),