1use 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 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 pub id: LifetimeParamId,
116 pub index: u32,
117}
118
119#[derive(Copy, Clone, PartialEq, Eq, Hash)]
120pub 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 Anon,
143
144 Named(SolverDefId),
149
150 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 }
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);