rustc_type_ir/
flags.rs

1use crate::inherent::*;
2use crate::visit::Flags;
3use crate::{self as ty, Interner};
4
5bitflags::bitflags! {
6    /// Flags that we track on types. These flags are propagated upwards
7    /// through the type during type construction, so that we can quickly check
8    /// whether the type has various kinds of types in it without recursing
9    /// over the type itself.
10    #[derive(Debug, PartialEq, Eq, Clone, Copy)]
11    pub struct TypeFlags: u32 {
12        // Does this have parameters? Used to determine whether instantiation is
13        // required.
14        /// Does this have `Param`?
15        const HAS_TY_PARAM                = 1 << 0;
16        /// Does this have `ReEarlyParam`?
17        const HAS_RE_PARAM                = 1 << 1;
18        /// Does this have `ConstKind::Param`?
19        const HAS_CT_PARAM                = 1 << 2;
20
21        const HAS_PARAM                   = TypeFlags::HAS_TY_PARAM.bits()
22                                          | TypeFlags::HAS_RE_PARAM.bits()
23                                          | TypeFlags::HAS_CT_PARAM.bits();
24
25        /// Does this have `Infer`?
26        const HAS_TY_INFER                = 1 << 3;
27        /// Does this have `ReVar`?
28        const HAS_RE_INFER                = 1 << 4;
29        /// Does this have `ConstKind::Infer`?
30        const HAS_CT_INFER                = 1 << 5;
31
32        /// Does this have inference variables? Used to determine whether
33        /// inference is required.
34        const HAS_INFER                   = TypeFlags::HAS_TY_INFER.bits()
35                                          | TypeFlags::HAS_RE_INFER.bits()
36                                          | TypeFlags::HAS_CT_INFER.bits();
37
38        /// Does this have `Placeholder`?
39        const HAS_TY_PLACEHOLDER          = 1 << 6;
40        /// Does this have `RePlaceholder`?
41        const HAS_RE_PLACEHOLDER          = 1 << 7;
42        /// Does this have `ConstKind::Placeholder`?
43        const HAS_CT_PLACEHOLDER          = 1 << 8;
44
45        /// Does this have placeholders?
46        const HAS_PLACEHOLDER             = TypeFlags::HAS_TY_PLACEHOLDER.bits()
47                                          | TypeFlags::HAS_RE_PLACEHOLDER.bits()
48                                          | TypeFlags::HAS_CT_PLACEHOLDER.bits();
49
50        /// `true` if there are "names" of regions and so forth
51        /// that are local to a particular fn/inferctxt
52        const HAS_FREE_LOCAL_REGIONS      = 1 << 9;
53
54        /// `true` if there are "names" of types and regions and so forth
55        /// that are local to a particular fn
56        const HAS_FREE_LOCAL_NAMES        = TypeFlags::HAS_TY_PARAM.bits()
57                                          | TypeFlags::HAS_CT_PARAM.bits()
58                                          | TypeFlags::HAS_TY_INFER.bits()
59                                          | TypeFlags::HAS_CT_INFER.bits()
60                                          | TypeFlags::HAS_TY_PLACEHOLDER.bits()
61                                          | TypeFlags::HAS_CT_PLACEHOLDER.bits()
62                                          // We consider 'freshened' types and constants
63                                          // to depend on a particular fn.
64                                          // The freshening process throws away information,
65                                          // which can make things unsuitable for use in a global
66                                          // cache. Note that there is no 'fresh lifetime' flag -
67                                          // freshening replaces all lifetimes with `ReErased`,
68                                          // which is different from how types/const are freshened.
69                                          | TypeFlags::HAS_TY_FRESH.bits()
70                                          | TypeFlags::HAS_CT_FRESH.bits()
71                                          | TypeFlags::HAS_FREE_LOCAL_REGIONS.bits()
72                                          | TypeFlags::HAS_RE_ERASED.bits();
73
74        /// Does this have `Projection`?
75        const HAS_TY_PROJECTION           = 1 << 10;
76        /// Does this have `Free` aliases?
77        const HAS_TY_FREE_ALIAS                 = 1 << 11;
78        /// Does this have `Opaque`?
79        const HAS_TY_OPAQUE               = 1 << 12;
80        /// Does this have `Inherent`?
81        const HAS_TY_INHERENT             = 1 << 13;
82        /// Does this have `ConstKind::Unevaluated`?
83        const HAS_CT_PROJECTION           = 1 << 14;
84
85        /// Does this have `Alias` or `ConstKind::Unevaluated`?
86        ///
87        /// Rephrased, could this term be normalized further?
88        const HAS_ALIAS                   = TypeFlags::HAS_TY_PROJECTION.bits()
89                                          | TypeFlags::HAS_TY_FREE_ALIAS.bits()
90                                          | TypeFlags::HAS_TY_OPAQUE.bits()
91                                          | TypeFlags::HAS_TY_INHERENT.bits()
92                                          | TypeFlags::HAS_CT_PROJECTION.bits();
93
94        /// Is an error type/lifetime/const reachable?
95        const HAS_ERROR                   = 1 << 15;
96
97        /// Does this have any region that "appears free" in the type?
98        /// Basically anything but `ReBound` and `ReErased`.
99        const HAS_FREE_REGIONS            = 1 << 16;
100
101        /// Does this have any `ReBound` regions?
102        const HAS_RE_BOUND                = 1 << 17;
103        /// Does this have any `Bound` types?
104        const HAS_TY_BOUND                = 1 << 18;
105        /// Does this have any `ConstKind::Bound` consts?
106        const HAS_CT_BOUND                = 1 << 19;
107        /// Does this have any bound variables?
108        /// Used to check if a global bound is safe to evaluate.
109        const HAS_BOUND_VARS              = TypeFlags::HAS_RE_BOUND.bits()
110                                          | TypeFlags::HAS_TY_BOUND.bits()
111                                          | TypeFlags::HAS_CT_BOUND.bits();
112
113        /// Does this have any `ReErased` regions?
114        const HAS_RE_ERASED               = 1 << 20;
115
116        /// Does this value have parameters/placeholders/inference variables which could be
117        /// replaced later, in a way that would change the results of `impl` specialization?
118        const STILL_FURTHER_SPECIALIZABLE = TypeFlags::HAS_TY_PARAM.bits()
119                                          | TypeFlags::HAS_TY_PLACEHOLDER.bits()
120                                          | TypeFlags::HAS_TY_INFER.bits()
121                                          | TypeFlags::HAS_CT_PARAM.bits()
122                                          | TypeFlags::HAS_CT_PLACEHOLDER.bits()
123                                          | TypeFlags::HAS_CT_INFER.bits();
124
125        /// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
126        const HAS_TY_FRESH                = 1 << 21;
127
128        /// Does this value have `InferConst::Fresh`?
129        const HAS_CT_FRESH                = 1 << 22;
130
131        /// Does this have any binders with bound vars (e.g. that need to be anonymized)?
132        const HAS_BINDER_VARS             = 1 << 23;
133
134        /// Does this type have any coroutine witnesses in it?
135        // FIXME: This should probably be changed to track whether the type has any
136        // *coroutines* in it, though this will happen if we remove coroutine witnesses
137        // altogether.
138        const HAS_TY_CORO                 = 1 << 24;
139    }
140}
141
142#[derive(Debug)]
143pub struct FlagComputation<I> {
144    pub flags: TypeFlags,
145
146    /// see `Ty::outer_exclusive_binder` for details
147    pub outer_exclusive_binder: ty::DebruijnIndex,
148
149    interner: std::marker::PhantomData<I>,
150}
151
152impl<I: Interner> FlagComputation<I> {
153    fn new() -> FlagComputation<I> {
154        FlagComputation {
155            flags: TypeFlags::empty(),
156            outer_exclusive_binder: ty::INNERMOST,
157            interner: std::marker::PhantomData,
158        }
159    }
160
161    #[allow(rustc::usage_of_ty_tykind)]
162    pub fn for_kind(kind: &ty::TyKind<I>) -> FlagComputation<I> {
163        let mut result = FlagComputation::new();
164        result.add_kind(kind);
165        result
166    }
167
168    pub fn for_predicate(binder: ty::Binder<I, ty::PredicateKind<I>>) -> FlagComputation<I> {
169        let mut result = FlagComputation::new();
170        result.add_predicate(binder);
171        result
172    }
173
174    pub fn for_const_kind(kind: &ty::ConstKind<I>) -> FlagComputation<I> {
175        let mut result = FlagComputation::new();
176        result.add_const_kind(kind);
177        result
178    }
179
180    pub fn for_clauses(clauses: &[I::Clause]) -> FlagComputation<I> {
181        let mut result = FlagComputation::new();
182        for c in clauses {
183            result.add_flags(c.as_predicate().flags());
184            result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
185        }
186        result
187    }
188
189    fn add_flags(&mut self, flags: TypeFlags) {
190        self.flags = self.flags | flags;
191    }
192
193    /// indicates that `self` refers to something at binding level `binder`
194    fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
195        let exclusive_binder = binder.shifted_in(1);
196        self.add_exclusive_binder(exclusive_binder);
197    }
198
199    /// indicates that `self` refers to something *inside* binding
200    /// level `binder` -- not bound by `binder`, but bound by the next
201    /// binder internal to it
202    fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
203        self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
204    }
205
206    /// Adds the flags/depth from a set of types that appear within the current type, but within a
207    /// region binder.
208    fn bound_computation<T, F>(&mut self, value: ty::Binder<I, T>, f: F)
209    where
210        F: FnOnce(&mut Self, T),
211    {
212        let mut computation = FlagComputation::new();
213
214        if !value.bound_vars().is_empty() {
215            computation.add_flags(TypeFlags::HAS_BINDER_VARS);
216        }
217
218        f(&mut computation, value.skip_binder());
219
220        self.add_flags(computation.flags);
221
222        // The types that contributed to `computation` occurred within
223        // a region binder, so subtract one from the region depth
224        // within when adding the depth to `self`.
225        let outer_exclusive_binder = computation.outer_exclusive_binder;
226        if outer_exclusive_binder > ty::INNERMOST {
227            self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
228        } // otherwise, this binder captures nothing
229    }
230
231    #[allow(rustc::usage_of_ty_tykind)]
232    fn add_kind(&mut self, kind: &ty::TyKind<I>) {
233        match *kind {
234            ty::Bool
235            | ty::Char
236            | ty::Int(_)
237            | ty::Float(_)
238            | ty::Uint(_)
239            | ty::Never
240            | ty::Str
241            | ty::Foreign(..) => {}
242
243            ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
244
245            ty::Param(_) => {
246                self.add_flags(TypeFlags::HAS_TY_PARAM);
247            }
248
249            ty::Closure(_, args) | ty::Coroutine(_, args) | ty::CoroutineClosure(_, args) => {
250                self.add_args(args.as_slice());
251            }
252
253            ty::CoroutineWitness(_, args) => {
254                self.add_flags(TypeFlags::HAS_TY_CORO);
255                self.add_args(args.as_slice());
256            }
257
258            ty::Bound(debruijn, _) => {
259                self.add_bound_var(debruijn);
260                self.add_flags(TypeFlags::HAS_TY_BOUND);
261            }
262
263            ty::Placeholder(..) => {
264                self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
265            }
266
267            ty::Infer(infer) => match infer {
268                ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
269                    self.add_flags(TypeFlags::HAS_TY_FRESH)
270                }
271
272                ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
273                    self.add_flags(TypeFlags::HAS_TY_INFER)
274                }
275            },
276
277            ty::Adt(_, args) => {
278                self.add_args(args.as_slice());
279            }
280
281            ty::Alias(kind, data) => {
282                self.add_flags(match kind {
283                    ty::Projection => TypeFlags::HAS_TY_PROJECTION,
284                    ty::Free => TypeFlags::HAS_TY_FREE_ALIAS,
285                    ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
286                    ty::Inherent => TypeFlags::HAS_TY_INHERENT,
287                });
288
289                self.add_alias_ty(data);
290            }
291
292            ty::Dynamic(obj, r, _) => {
293                for predicate in obj.iter() {
294                    self.bound_computation(predicate, |computation, predicate| match predicate {
295                        ty::ExistentialPredicate::Trait(tr) => {
296                            computation.add_args(tr.args.as_slice())
297                        }
298                        ty::ExistentialPredicate::Projection(p) => {
299                            computation.add_existential_projection(&p);
300                        }
301                        ty::ExistentialPredicate::AutoTrait(_) => {}
302                    });
303                }
304
305                self.add_region(r);
306            }
307
308            ty::Array(tt, len) => {
309                self.add_ty(tt);
310                self.add_const(len);
311            }
312
313            ty::Pat(ty, pat) => {
314                self.add_ty(ty);
315                self.add_ty_pat(pat);
316            }
317
318            ty::Slice(tt) => self.add_ty(tt),
319
320            ty::RawPtr(ty, _) => {
321                self.add_ty(ty);
322            }
323
324            ty::Ref(r, ty, _) => {
325                self.add_region(r);
326                self.add_ty(ty);
327            }
328
329            ty::Tuple(types) => {
330                self.add_tys(types);
331            }
332
333            ty::FnDef(_, args) => {
334                self.add_args(args.as_slice());
335            }
336
337            ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
338                computation.add_tys(sig_tys.inputs_and_output);
339            }),
340
341            ty::UnsafeBinder(bound_ty) => {
342                self.bound_computation(bound_ty.into(), |computation, ty| {
343                    computation.add_ty(ty);
344                })
345            }
346        }
347    }
348
349    fn add_ty_pat(&mut self, pat: <I as Interner>::Pat) {
350        self.add_flags(pat.flags());
351    }
352
353    fn add_predicate(&mut self, binder: ty::Binder<I, ty::PredicateKind<I>>) {
354        self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
355    }
356
357    fn add_predicate_atom(&mut self, atom: ty::PredicateKind<I>) {
358        match atom {
359            ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
360                self.add_args(trait_pred.trait_ref.args.as_slice());
361            }
362            ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
363                trait_ref,
364                constness: _,
365            })) => {
366                self.add_args(trait_ref.args.as_slice());
367            }
368            ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
369                a,
370                b,
371            ))) => {
372                self.add_region(a);
373                self.add_region(b);
374            }
375            ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
376                ty,
377                region,
378            ))) => {
379                self.add_ty(ty);
380                self.add_region(region);
381            }
382            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
383                self.add_const(ct);
384                self.add_ty(ty);
385            }
386            ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
387                self.add_ty(a);
388                self.add_ty(b);
389            }
390            ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
391                self.add_ty(a);
392                self.add_ty(b);
393            }
394            ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
395                projection_term,
396                term,
397            })) => {
398                self.add_alias_term(projection_term);
399                self.add_term(term);
400            }
401            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(term)) => {
402                self.add_term(term);
403            }
404            ty::PredicateKind::DynCompatible(_def_id) => {}
405            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
406                self.add_const(uv);
407            }
408            ty::PredicateKind::ConstEquate(expected, found) => {
409                self.add_const(expected);
410                self.add_const(found);
411            }
412            ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
413                self.add_alias_term(alias);
414                self.add_term(term);
415            }
416            ty::PredicateKind::AliasRelate(t1, t2, _) => {
417                self.add_term(t1);
418                self.add_term(t2);
419            }
420            ty::PredicateKind::Clause(ty::ClauseKind::UnstableFeature(_sym)) => {}
421            ty::PredicateKind::Ambiguous => {}
422        }
423    }
424
425    fn add_ty(&mut self, ty: I::Ty) {
426        self.add_flags(ty.flags());
427        self.add_exclusive_binder(ty.outer_exclusive_binder());
428    }
429
430    fn add_tys(&mut self, tys: I::Tys) {
431        for ty in tys.iter() {
432            self.add_ty(ty);
433        }
434    }
435
436    fn add_region(&mut self, r: I::Region) {
437        self.add_flags(r.flags());
438        if let ty::ReBound(debruijn, _) = r.kind() {
439            self.add_bound_var(debruijn);
440        }
441    }
442
443    fn add_const(&mut self, c: I::Const) {
444        self.add_flags(c.flags());
445        self.add_exclusive_binder(c.outer_exclusive_binder());
446    }
447
448    fn add_const_kind(&mut self, c: &ty::ConstKind<I>) {
449        match *c {
450            ty::ConstKind::Unevaluated(uv) => {
451                self.add_args(uv.args.as_slice());
452                self.add_flags(TypeFlags::HAS_CT_PROJECTION);
453            }
454            ty::ConstKind::Infer(infer) => match infer {
455                ty::InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
456                ty::InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
457            },
458            ty::ConstKind::Bound(debruijn, _) => {
459                self.add_bound_var(debruijn);
460                self.add_flags(TypeFlags::HAS_CT_BOUND);
461            }
462            ty::ConstKind::Param(_) => {
463                self.add_flags(TypeFlags::HAS_CT_PARAM);
464            }
465            ty::ConstKind::Placeholder(_) => {
466                self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
467            }
468            ty::ConstKind::Value(cv) => self.add_ty(cv.ty()),
469            ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()),
470            ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
471        }
472    }
473
474    fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<I>) {
475        self.add_args(projection.args.as_slice());
476        match projection.term.kind() {
477            ty::TermKind::Ty(ty) => self.add_ty(ty),
478            ty::TermKind::Const(ct) => self.add_const(ct),
479        }
480    }
481
482    fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<I>) {
483        self.add_args(alias_ty.args.as_slice());
484    }
485
486    fn add_alias_term(&mut self, alias_term: ty::AliasTerm<I>) {
487        self.add_args(alias_term.args.as_slice());
488    }
489
490    fn add_args(&mut self, args: &[I::GenericArg]) {
491        for arg in args {
492            match arg.kind() {
493                ty::GenericArgKind::Type(ty) => self.add_ty(ty),
494                ty::GenericArgKind::Lifetime(lt) => self.add_region(lt),
495                ty::GenericArgKind::Const(ct) => self.add_const(ct),
496            }
497        }
498    }
499
500    fn add_term(&mut self, term: I::Term) {
501        match term.kind() {
502            ty::TermKind::Ty(ty) => self.add_ty(ty),
503            ty::TermKind::Const(ct) => self.add_const(ct),
504        }
505    }
506}