Skip to main content

hir_ty/next_solver/
region.rs

1//! Things related to regions.
2
3use hir_def::LifetimeParamId;
4use intern::{Interned, InternedRef, impl_internable};
5use macros::GenericTypeVisitable;
6use rustc_type_ir::{
7    BoundVarIndexKind, DebruijnIndex, Flags, GenericTypeVisitable, INNERMOST, RegionVid, TypeFlags,
8    TypeFoldable, TypeVisitable,
9    inherent::{IntoKind, SliceLike},
10    relate::Relate,
11};
12
13use crate::next_solver::{
14    GenericArg, OutlivesPredicate, impl_foldable_for_interned_slice, impl_stored_interned,
15    interned_slice,
16};
17
18use super::{SolverDefId, interner::DbInterner};
19
20pub type RegionKind<'db> = rustc_type_ir::RegionKind<DbInterner<'db>>;
21pub type RegionConstraint<'db> = rustc_type_ir::RegionConstraint<DbInterner<'db>>;
22
23#[derive(Clone, Copy, PartialEq, Eq, Hash)]
24pub struct Region<'db> {
25    pub(super) interned: InternedRef<'db, RegionInterned>,
26}
27
28#[derive(PartialEq, Eq, Hash, GenericTypeVisitable)]
29#[repr(align(4))] // Required for `GenericArg` bit-tagging.
30pub(super) struct RegionInterned(RegionKind<'static>);
31
32impl_internable!(gc; RegionInterned);
33impl_stored_interned!(RegionInterned, Region, StoredRegion);
34
35const _: () = {
36    const fn is_copy<T: Copy>() {}
37    is_copy::<Region<'static>>();
38};
39
40impl<'db> Region<'db> {
41    pub fn new(_interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self {
42        let kind = unsafe { std::mem::transmute::<RegionKind<'db>, RegionKind<'static>>(kind) };
43        Self { interned: Interned::new_gc(RegionInterned(kind)) }
44    }
45
46    pub fn inner(&self) -> &RegionKind<'db> {
47        let inner = &self.interned.0;
48        unsafe { std::mem::transmute::<&RegionKind<'static>, &RegionKind<'db>>(inner) }
49    }
50
51    pub fn new_early_param(
52        interner: DbInterner<'db>,
53        early_bound_region: EarlyParamRegion,
54    ) -> Self {
55        Region::new(interner, RegionKind::ReEarlyParam(early_bound_region))
56    }
57
58    pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderRegion<'db>) -> Self {
59        Region::new(interner, RegionKind::RePlaceholder(placeholder))
60    }
61
62    pub fn new_var(interner: DbInterner<'db>, v: RegionVid) -> Region<'db> {
63        Region::new(interner, RegionKind::ReVar(v))
64    }
65
66    pub fn new_erased(interner: DbInterner<'db>) -> Region<'db> {
67        interner.default_types().regions.erased
68    }
69
70    pub fn new_bound(
71        interner: DbInterner<'db>,
72        index: DebruijnIndex,
73        bound: BoundRegion<'db>,
74    ) -> Region<'db> {
75        Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(index), bound))
76    }
77
78    pub fn new_late_param(
79        interner: DbInterner<'db>,
80        scope: SolverDefId<'db>,
81        bound_region: BoundRegion<'db>,
82    ) -> Region<'db> {
83        let late_bound_region = LateParamRegion { scope, bound_region };
84        Region::new(interner, RegionKind::ReLateParam(late_bound_region))
85    }
86
87    pub fn is_placeholder(&self) -> bool {
88        matches!(self.inner(), RegionKind::RePlaceholder(..))
89    }
90
91    pub fn is_static(&self) -> bool {
92        matches!(self.inner(), RegionKind::ReStatic)
93    }
94
95    pub fn is_erased(&self) -> bool {
96        matches!(self.inner(), RegionKind::ReErased)
97    }
98
99    pub fn is_var(&self) -> bool {
100        matches!(self.inner(), RegionKind::ReVar(_))
101    }
102
103    pub fn is_error(&self) -> bool {
104        matches!(self.inner(), RegionKind::ReError(_))
105    }
106
107    pub fn error(interner: DbInterner<'db>) -> Self {
108        interner.default_types().regions.error
109    }
110
111    pub fn type_flags(&self) -> TypeFlags {
112        let mut flags = TypeFlags::empty();
113
114        match &self.inner() {
115            RegionKind::ReVar(..) => {
116                flags |= TypeFlags::HAS_FREE_REGIONS;
117                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
118                flags |= TypeFlags::HAS_RE_INFER;
119            }
120            RegionKind::RePlaceholder(..) => {
121                flags |= TypeFlags::HAS_FREE_REGIONS;
122                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
123                flags |= TypeFlags::HAS_RE_PLACEHOLDER;
124            }
125            RegionKind::ReEarlyParam(..) => {
126                flags |= TypeFlags::HAS_FREE_REGIONS;
127                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
128                flags |= TypeFlags::HAS_RE_PARAM;
129            }
130            RegionKind::ReLateParam(..) => {
131                flags |= TypeFlags::HAS_FREE_REGIONS;
132                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
133            }
134            RegionKind::ReStatic => {
135                flags |= TypeFlags::HAS_FREE_REGIONS;
136            }
137            RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => {
138                flags |= TypeFlags::HAS_RE_BOUND;
139                flags |= TypeFlags::HAS_CANONICAL_BOUND;
140            }
141            RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => {
142                flags |= TypeFlags::HAS_RE_BOUND;
143            }
144            RegionKind::ReErased => {
145                flags |= TypeFlags::HAS_RE_ERASED;
146            }
147            RegionKind::ReError(..) => {
148                flags |= TypeFlags::HAS_FREE_REGIONS;
149                flags |= TypeFlags::HAS_RE_ERROR;
150            }
151        }
152
153        flags
154    }
155}
156
157pub type PlaceholderRegion<'db> = rustc_type_ir::PlaceholderRegion<DbInterner<'db>>;
158
159#[derive(Copy, Clone, PartialEq, Eq, Hash)]
160pub struct EarlyParamRegion {
161    // FIXME: See `ParamTy`.
162    pub id: LifetimeParamId,
163    pub index: u32,
164}
165
166#[derive(Copy, Clone, PartialEq, Eq, Hash, GenericTypeVisitable)]
167/// Represents a liberated late-bound function lifetime parameter.
168///
169/// This denotes some region at least as big as `scope`. It is similar to a placeholder region
170/// created when entering a binder, except it always lives in the root universe.
171pub struct LateParamRegion<'db> {
172    pub scope: SolverDefId<'db>,
173    pub bound_region: BoundRegion<'db>,
174}
175
176impl std::fmt::Debug for LateParamRegion<'_> {
177    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
178        write!(f, "ReLateParam({:?}, {:?})", self.scope, self.bound_region)
179    }
180}
181
182pub type BoundRegion<'db> = rustc_type_ir::BoundRegion<DbInterner<'db>>;
183pub type BoundRegionKind<'db> = rustc_type_ir::BoundRegionKind<DbInterner<'db>>;
184
185impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion {
186    fn index(self) -> u32 {
187        self.index
188    }
189}
190
191impl std::fmt::Debug for EarlyParamRegion {
192    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
193        write!(f, "#{}", self.index)
194        // write!(f, "{}/#{}", self.name, self.index)
195    }
196}
197
198impl std::fmt::Debug for Region<'_> {
199    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
200        self.kind().fmt(f)
201    }
202}
203
204impl<'db> IntoKind for Region<'db> {
205    type Kind = RegionKind<'db>;
206
207    fn kind(self) -> Self::Kind {
208        *self.inner()
209    }
210}
211
212impl<'db> TypeVisitable<DbInterner<'db>> for Region<'db> {
213    fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
214        &self,
215        visitor: &mut V,
216    ) -> V::Result {
217        visitor.visit_region(*self)
218    }
219}
220
221impl<'db> TypeFoldable<DbInterner<'db>> for Region<'db> {
222    fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
223        self,
224        folder: &mut F,
225    ) -> Result<Self, F::Error> {
226        folder.try_fold_region(self)
227    }
228    fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
229        folder.fold_region(self)
230    }
231}
232
233impl<'db> Relate<DbInterner<'db>> for Region<'db> {
234    fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
235        relation: &mut R,
236        a: Self,
237        b: Self,
238    ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
239        relation.regions(a, b)
240    }
241}
242
243impl<'db> Flags for Region<'db> {
244    fn flags(&self) -> rustc_type_ir::TypeFlags {
245        self.type_flags()
246    }
247
248    fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
249        match &self.inner() {
250            RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1),
251            _ => INNERMOST,
252        }
253    }
254}
255
256impl<'db> rustc_type_ir::inherent::Region<DbInterner<'db>> for Region<'db> {
257    fn new_bound(
258        interner: DbInterner<'db>,
259        debruijn: DebruijnIndex,
260        var: BoundRegion<'db>,
261    ) -> Self {
262        Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), var))
263    }
264
265    fn new_anon_bound(
266        interner: DbInterner<'db>,
267        debruijn: DebruijnIndex,
268        var: rustc_type_ir::BoundVar,
269    ) -> Self {
270        Region::new(
271            interner,
272            RegionKind::ReBound(
273                BoundVarIndexKind::Bound(debruijn),
274                BoundRegion { var, kind: BoundRegionKind::Anon },
275            ),
276        )
277    }
278
279    fn new_canonical_bound(interner: DbInterner<'db>, var: rustc_type_ir::BoundVar) -> Self {
280        Region::new(
281            interner,
282            RegionKind::ReBound(
283                BoundVarIndexKind::Canonical,
284                BoundRegion { var, kind: BoundRegionKind::Anon },
285            ),
286        )
287    }
288
289    fn new_static(interner: DbInterner<'db>) -> Self {
290        interner.default_types().regions.statik
291    }
292
293    fn new_placeholder(interner: DbInterner<'db>, var: PlaceholderRegion<'db>) -> Self {
294        Region::new(interner, RegionKind::RePlaceholder(var))
295    }
296}
297
298impl<'db, V: super::WorldExposer> GenericTypeVisitable<V> for Region<'db> {
299    fn generic_visit_with(&self, visitor: &mut V) {
300        if visitor.on_interned(self.interned).is_continue() {
301            self.kind().generic_visit_with(visitor);
302        }
303    }
304}
305
306type GenericArgOutlivesPredicate<'db> = OutlivesPredicate<'db, GenericArg<'db>>;
307
308interned_slice!(
309    RegionAssumptionsStorage,
310    RegionAssumptions,
311    StoredRegionAssumptions,
312    region_assumptions,
313    GenericArgOutlivesPredicate<'db>,
314    GenericArgOutlivesPredicate<'static>,
315);
316impl_foldable_for_interned_slice!(RegionAssumptions);