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