hir_ty/next_solver/
region.rs

1//! Things related to regions.
2
3use hir_def::LifetimeParamId;
4use intern::Symbol;
5use rustc_type_ir::{
6    BoundVar, BoundVarIndexKind, DebruijnIndex, Flags, INNERMOST, RegionVid, TypeFlags,
7    TypeFoldable, TypeVisitable,
8    inherent::{IntoKind, PlaceholderLike, SliceLike},
9    relate::Relate,
10};
11
12use crate::next_solver::{GenericArg, OutlivesPredicate};
13
14use super::{
15    ErrorGuaranteed, SolverDefId, interned_vec_db,
16    interner::{BoundVarKind, DbInterner, Placeholder},
17};
18
19pub type RegionKind<'db> = rustc_type_ir::RegionKind<DbInterner<'db>>;
20
21#[salsa::interned(constructor = new_)]
22pub struct Region<'db> {
23    #[returns(ref)]
24    kind_: RegionKind<'db>,
25}
26
27impl std::fmt::Debug for Region<'_> {
28    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
29        self.kind().fmt(f)
30    }
31}
32
33impl<'db> Region<'db> {
34    pub fn new(interner: DbInterner<'db>, kind: RegionKind<'db>) -> Self {
35        Region::new_(interner.db(), kind)
36    }
37
38    pub fn inner(&self) -> &RegionKind<'db> {
39        crate::with_attached_db(|db| {
40            let inner = self.kind_(db);
41            // SAFETY: The caller already has access to a `Region<'db>`, so borrowchecking will
42            // make sure that our returned value is valid for the lifetime `'db`.
43            unsafe { std::mem::transmute::<&RegionKind<'_>, &RegionKind<'db>>(inner) }
44        })
45    }
46
47    pub fn new_early_param(
48        interner: DbInterner<'db>,
49        early_bound_region: EarlyParamRegion,
50    ) -> Self {
51        Region::new(interner, RegionKind::ReEarlyParam(early_bound_region))
52    }
53
54    pub fn new_placeholder(interner: DbInterner<'db>, placeholder: PlaceholderRegion) -> Self {
55        Region::new(interner, RegionKind::RePlaceholder(placeholder))
56    }
57
58    pub fn new_var(interner: DbInterner<'db>, v: RegionVid) -> Region<'db> {
59        Region::new(interner, RegionKind::ReVar(v))
60    }
61
62    pub fn new_erased(interner: DbInterner<'db>) -> Region<'db> {
63        Region::new(interner, RegionKind::ReErased)
64    }
65
66    pub fn new_bound(
67        interner: DbInterner<'db>,
68        index: DebruijnIndex,
69        bound: BoundRegion,
70    ) -> Region<'db> {
71        Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(index), bound))
72    }
73
74    pub fn is_placeholder(&self) -> bool {
75        matches!(self.inner(), RegionKind::RePlaceholder(..))
76    }
77
78    pub fn is_static(&self) -> bool {
79        matches!(self.inner(), RegionKind::ReStatic)
80    }
81
82    pub fn is_erased(&self) -> bool {
83        matches!(self.inner(), RegionKind::ReErased)
84    }
85
86    pub fn is_var(&self) -> bool {
87        matches!(self.inner(), RegionKind::ReVar(_))
88    }
89
90    pub fn is_error(&self) -> bool {
91        matches!(self.inner(), RegionKind::ReError(_))
92    }
93
94    pub fn error(interner: DbInterner<'db>) -> Self {
95        Region::new(interner, RegionKind::ReError(ErrorGuaranteed))
96    }
97
98    pub fn type_flags(&self) -> TypeFlags {
99        let mut flags = TypeFlags::empty();
100
101        match &self.inner() {
102            RegionKind::ReVar(..) => {
103                flags |= TypeFlags::HAS_FREE_REGIONS;
104                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
105                flags |= TypeFlags::HAS_RE_INFER;
106            }
107            RegionKind::RePlaceholder(..) => {
108                flags |= TypeFlags::HAS_FREE_REGIONS;
109                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
110                flags |= TypeFlags::HAS_RE_PLACEHOLDER;
111            }
112            RegionKind::ReEarlyParam(..) => {
113                flags |= TypeFlags::HAS_FREE_REGIONS;
114                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
115                flags |= TypeFlags::HAS_RE_PARAM;
116            }
117            RegionKind::ReLateParam(..) => {
118                flags |= TypeFlags::HAS_FREE_REGIONS;
119                flags |= TypeFlags::HAS_FREE_LOCAL_REGIONS;
120            }
121            RegionKind::ReStatic => {
122                flags |= TypeFlags::HAS_FREE_REGIONS;
123            }
124            RegionKind::ReBound(BoundVarIndexKind::Canonical, ..) => {
125                flags |= TypeFlags::HAS_RE_BOUND;
126                flags |= TypeFlags::HAS_CANONICAL_BOUND;
127            }
128            RegionKind::ReBound(BoundVarIndexKind::Bound(..), ..) => {
129                flags |= TypeFlags::HAS_RE_BOUND;
130            }
131            RegionKind::ReErased => {
132                flags |= TypeFlags::HAS_RE_ERASED;
133            }
134            RegionKind::ReError(..) => {
135                flags |= TypeFlags::HAS_FREE_REGIONS;
136                flags |= TypeFlags::HAS_ERROR;
137            }
138        }
139
140        flags
141    }
142}
143
144pub type PlaceholderRegion = Placeholder<BoundRegion>;
145
146#[derive(Copy, Clone, PartialEq, Eq, Hash)]
147pub struct EarlyParamRegion {
148    // FIXME: See `ParamTy`.
149    pub id: LifetimeParamId,
150    pub index: u32,
151}
152
153#[derive(Copy, Clone, PartialEq, Eq, Hash)]
154/// The parameter representation of late-bound function parameters, "some region
155/// at least as big as the scope `fr.scope`".
156///
157/// Similar to a placeholder region as we create `LateParam` regions when entering a binder
158/// except they are always in the root universe and instead of using a boundvar to distinguish
159/// between others we use the `DefId` of the parameter. For this reason the `bound_region` field
160/// should basically always be `BoundRegionKind::Named` as otherwise there is no way of telling
161/// different parameters apart.
162pub struct LateParamRegion {
163    pub scope: SolverDefId,
164    pub bound_region: BoundRegionKind,
165}
166
167impl std::fmt::Debug for LateParamRegion {
168    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169        write!(f, "ReLateParam({:?}, {:?})", self.scope, self.bound_region)
170    }
171}
172
173#[derive(Copy, Clone, PartialEq, Eq, Hash)]
174pub enum BoundRegionKind {
175    /// An anonymous region parameter for a given fn (&T)
176    Anon,
177
178    /// Named region parameters for functions (a in &'a T)
179    ///
180    /// The `DefId` is needed to distinguish free regions in
181    /// the event of shadowing.
182    Named(SolverDefId),
183
184    /// Anonymous region for the implicit env pointer parameter
185    /// to a closure
186    ClosureEnv,
187}
188
189impl std::fmt::Debug for BoundRegionKind {
190    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191        match *self {
192            BoundRegionKind::Anon => write!(f, "BrAnon"),
193            BoundRegionKind::Named(did) => {
194                write!(f, "BrNamed({did:?})")
195            }
196            BoundRegionKind::ClosureEnv => write!(f, "BrEnv"),
197        }
198    }
199}
200
201#[derive(Copy, Clone, PartialEq, Eq, Hash)]
202pub struct BoundRegion {
203    pub var: BoundVar,
204    pub kind: BoundRegionKind,
205}
206
207impl rustc_type_ir::inherent::ParamLike for EarlyParamRegion {
208    fn index(self) -> u32 {
209        self.index
210    }
211}
212
213impl std::fmt::Debug for EarlyParamRegion {
214    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
215        write!(f, "#{}", self.index)
216        // write!(f, "{}/#{}", self.name, self.index)
217    }
218}
219
220impl<'db> rustc_type_ir::inherent::BoundVarLike<DbInterner<'db>> for BoundRegion {
221    fn var(self) -> BoundVar {
222        self.var
223    }
224
225    fn assert_eq(self, var: BoundVarKind) {
226        assert_eq!(self.kind, var.expect_region())
227    }
228}
229
230impl core::fmt::Debug for BoundRegion {
231    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232        match &self.kind {
233            BoundRegionKind::Anon => write!(f, "{:?}", self.var),
234            BoundRegionKind::ClosureEnv => write!(f, "{:?}.Env", self.var),
235            BoundRegionKind::Named(def) => {
236                write!(f, "{:?}.Named({:?})", self.var, def)
237            }
238        }
239    }
240}
241
242impl BoundRegionKind {
243    pub fn is_named(&self) -> bool {
244        matches!(self, BoundRegionKind::Named(_))
245    }
246
247    pub fn get_name(&self) -> Option<Symbol> {
248        None
249    }
250
251    pub fn get_id(&self) -> Option<SolverDefId> {
252        match self {
253            BoundRegionKind::Named(id) => Some(*id),
254            _ => None,
255        }
256    }
257}
258
259impl<'db> IntoKind for Region<'db> {
260    type Kind = RegionKind<'db>;
261
262    fn kind(self) -> Self::Kind {
263        *self.inner()
264    }
265}
266
267impl<'db> TypeVisitable<DbInterner<'db>> for Region<'db> {
268    fn visit_with<V: rustc_type_ir::TypeVisitor<DbInterner<'db>>>(
269        &self,
270        visitor: &mut V,
271    ) -> V::Result {
272        visitor.visit_region(*self)
273    }
274}
275
276impl<'db> TypeFoldable<DbInterner<'db>> for Region<'db> {
277    fn try_fold_with<F: rustc_type_ir::FallibleTypeFolder<DbInterner<'db>>>(
278        self,
279        folder: &mut F,
280    ) -> Result<Self, F::Error> {
281        folder.try_fold_region(self)
282    }
283    fn fold_with<F: rustc_type_ir::TypeFolder<DbInterner<'db>>>(self, folder: &mut F) -> Self {
284        folder.fold_region(self)
285    }
286}
287
288impl<'db> Relate<DbInterner<'db>> for Region<'db> {
289    fn relate<R: rustc_type_ir::relate::TypeRelation<DbInterner<'db>>>(
290        relation: &mut R,
291        a: Self,
292        b: Self,
293    ) -> rustc_type_ir::relate::RelateResult<DbInterner<'db>, Self> {
294        relation.regions(a, b)
295    }
296}
297
298impl<'db> Flags for Region<'db> {
299    fn flags(&self) -> rustc_type_ir::TypeFlags {
300        self.type_flags()
301    }
302
303    fn outer_exclusive_binder(&self) -> rustc_type_ir::DebruijnIndex {
304        match &self.inner() {
305            RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), _) => debruijn.shifted_in(1),
306            _ => INNERMOST,
307        }
308    }
309}
310
311impl<'db> rustc_type_ir::inherent::Region<DbInterner<'db>> for Region<'db> {
312    fn new_bound(
313        interner: DbInterner<'db>,
314        debruijn: rustc_type_ir::DebruijnIndex,
315        var: BoundRegion,
316    ) -> Self {
317        Region::new(interner, RegionKind::ReBound(BoundVarIndexKind::Bound(debruijn), var))
318    }
319
320    fn new_anon_bound(
321        interner: DbInterner<'db>,
322        debruijn: rustc_type_ir::DebruijnIndex,
323        var: rustc_type_ir::BoundVar,
324    ) -> Self {
325        Region::new(
326            interner,
327            RegionKind::ReBound(
328                BoundVarIndexKind::Bound(debruijn),
329                BoundRegion { var, kind: BoundRegionKind::Anon },
330            ),
331        )
332    }
333
334    fn new_canonical_bound(interner: DbInterner<'db>, var: rustc_type_ir::BoundVar) -> Self {
335        Region::new(
336            interner,
337            RegionKind::ReBound(
338                BoundVarIndexKind::Canonical,
339                BoundRegion { var, kind: BoundRegionKind::Anon },
340            ),
341        )
342    }
343
344    fn new_static(interner: DbInterner<'db>) -> Self {
345        Region::new(interner, RegionKind::ReStatic)
346    }
347
348    fn new_placeholder(
349        interner: DbInterner<'db>,
350        var: <DbInterner<'db> as rustc_type_ir::Interner>::PlaceholderRegion,
351    ) -> Self {
352        Region::new(interner, RegionKind::RePlaceholder(var))
353    }
354}
355
356impl<'db> PlaceholderLike<DbInterner<'db>> for PlaceholderRegion {
357    type Bound = BoundRegion;
358
359    fn universe(self) -> rustc_type_ir::UniverseIndex {
360        self.universe
361    }
362
363    fn var(self) -> rustc_type_ir::BoundVar {
364        self.bound.var
365    }
366
367    fn with_updated_universe(self, ui: rustc_type_ir::UniverseIndex) -> Self {
368        Placeholder { universe: ui, bound: self.bound }
369    }
370
371    fn new(ui: rustc_type_ir::UniverseIndex, bound: Self::Bound) -> Self {
372        Placeholder { universe: ui, bound }
373    }
374
375    fn new_anon(ui: rustc_type_ir::UniverseIndex, var: rustc_type_ir::BoundVar) -> Self {
376        Placeholder { universe: ui, bound: BoundRegion { var, kind: BoundRegionKind::Anon } }
377    }
378}
379
380type GenericArgOutlivesPredicate<'db> = OutlivesPredicate<'db, GenericArg<'db>>;
381
382interned_vec_db!(RegionAssumptions, GenericArgOutlivesPredicate);