hir_ty/next_solver/
region.rs

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