1use std::slice;
2
3use crate::ty::{self, GenericArg, GenericArgKind, InferConst, Ty, TypeFlags};
4
5#[derive(Debug)]
6pub struct FlagComputation {
7 pub flags: TypeFlags,
8
9 pub outer_exclusive_binder: ty::DebruijnIndex,
11}
12
13impl FlagComputation {
14 fn new() -> FlagComputation {
15 FlagComputation { flags: TypeFlags::empty(), outer_exclusive_binder: ty::INNERMOST }
16 }
17
18 #[allow(rustc::usage_of_ty_tykind)]
19 pub fn for_kind(kind: &ty::TyKind<'_>) -> FlagComputation {
20 let mut result = FlagComputation::new();
21 result.add_kind(kind);
22 result
23 }
24
25 pub fn for_predicate(binder: ty::Binder<'_, ty::PredicateKind<'_>>) -> FlagComputation {
26 let mut result = FlagComputation::new();
27 result.add_predicate(binder);
28 result
29 }
30
31 pub fn for_const_kind(kind: &ty::ConstKind<'_>) -> FlagComputation {
32 let mut result = FlagComputation::new();
33 result.add_const_kind(kind);
34 result
35 }
36
37 pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation {
38 let mut result = FlagComputation::new();
39 for c in clauses {
40 result.add_flags(c.as_predicate().flags());
41 result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
42 }
43 result
44 }
45
46 fn add_flags(&mut self, flags: TypeFlags) {
47 self.flags = self.flags | flags;
48 }
49
50 fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
52 let exclusive_binder = binder.shifted_in(1);
53 self.add_exclusive_binder(exclusive_binder);
54 }
55
56 fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
60 self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
61 }
62
63 fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
66 where
67 F: FnOnce(&mut Self, T),
68 {
69 let mut computation = FlagComputation::new();
70
71 if !value.bound_vars().is_empty() {
72 computation.add_flags(TypeFlags::HAS_BINDER_VARS);
73 }
74
75 f(&mut computation, value.skip_binder());
76
77 self.add_flags(computation.flags);
78
79 let outer_exclusive_binder = computation.outer_exclusive_binder;
83 if outer_exclusive_binder > ty::INNERMOST {
84 self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
85 } }
87
88 #[allow(rustc::usage_of_ty_tykind)]
89 fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
90 match kind {
91 &ty::Bool
92 | &ty::Char
93 | &ty::Int(_)
94 | &ty::Float(_)
95 | &ty::Uint(_)
96 | &ty::Never
97 | &ty::Str
98 | &ty::Foreign(..) => {}
99
100 &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
101
102 &ty::Param(_) => {
103 self.add_flags(TypeFlags::HAS_TY_PARAM);
104 }
105
106 &ty::Closure(_, args)
107 | &ty::Coroutine(_, args)
108 | &ty::CoroutineClosure(_, args)
109 | &ty::CoroutineWitness(_, args) => {
110 self.add_args(args);
111 }
112
113 &ty::Bound(debruijn, _) => {
114 self.add_bound_var(debruijn);
115 self.add_flags(TypeFlags::HAS_TY_BOUND);
116 }
117
118 &ty::Placeholder(..) => {
119 self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
120 }
121
122 &ty::Infer(infer) => match infer {
123 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
124 self.add_flags(TypeFlags::HAS_TY_FRESH)
125 }
126
127 ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
128 self.add_flags(TypeFlags::HAS_TY_INFER)
129 }
130 },
131
132 &ty::Adt(_, args) => {
133 self.add_args(args);
134 }
135
136 &ty::Alias(kind, data) => {
137 self.add_flags(match kind {
138 ty::Projection => TypeFlags::HAS_TY_PROJECTION,
139 ty::Weak => TypeFlags::HAS_TY_WEAK,
140 ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
141 ty::Inherent => TypeFlags::HAS_TY_INHERENT,
142 });
143
144 self.add_alias_ty(data);
145 }
146
147 &ty::Dynamic(obj, r, _) => {
148 for predicate in obj.iter() {
149 self.bound_computation(predicate, |computation, predicate| match predicate {
150 ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args),
151 ty::ExistentialPredicate::Projection(p) => {
152 computation.add_existential_projection(&p);
153 }
154 ty::ExistentialPredicate::AutoTrait(_) => {}
155 });
156 }
157
158 self.add_region(r);
159 }
160
161 &ty::Array(tt, len) => {
162 self.add_ty(tt);
163 self.add_const(len);
164 }
165
166 &ty::Pat(ty, pat) => {
167 self.add_ty(ty);
168 match *pat {
169 ty::PatternKind::Range { start, end } => {
170 self.add_const(start);
171 self.add_const(end);
172 }
173 }
174 }
175
176 &ty::Slice(tt) => self.add_ty(tt),
177
178 &ty::RawPtr(ty, _) => {
179 self.add_ty(ty);
180 }
181
182 &ty::Ref(r, ty, _) => {
183 self.add_region(r);
184 self.add_ty(ty);
185 }
186
187 &ty::Tuple(types) => {
188 self.add_tys(types);
189 }
190
191 &ty::FnDef(_, args) => {
192 self.add_args(args);
193 }
194
195 &ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
196 computation.add_tys(sig_tys.inputs_and_output);
197 }),
198
199 &ty::UnsafeBinder(bound_ty) => {
200 self.bound_computation(bound_ty.into(), |computation, ty| {
201 computation.add_ty(ty);
202 })
203 }
204 }
205 }
206
207 fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
208 self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
209 }
210
211 fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
212 match atom {
213 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
214 self.add_args(trait_pred.trait_ref.args);
215 }
216 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
217 trait_ref,
218 constness: _,
219 })) => {
220 self.add_args(trait_ref.args);
221 }
222 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
223 a,
224 b,
225 ))) => {
226 self.add_region(a);
227 self.add_region(b);
228 }
229 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
230 ty,
231 region,
232 ))) => {
233 self.add_ty(ty);
234 self.add_region(region);
235 }
236 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
237 self.add_const(ct);
238 self.add_ty(ty);
239 }
240 ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
241 self.add_ty(a);
242 self.add_ty(b);
243 }
244 ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
245 self.add_ty(a);
246 self.add_ty(b);
247 }
248 ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
249 projection_term,
250 term,
251 })) => {
252 self.add_alias_term(projection_term);
253 self.add_term(term);
254 }
255 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
256 self.add_args(slice::from_ref(&arg));
257 }
258 ty::PredicateKind::DynCompatible(_def_id) => {}
259 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
260 self.add_const(uv);
261 }
262 ty::PredicateKind::ConstEquate(expected, found) => {
263 self.add_const(expected);
264 self.add_const(found);
265 }
266 ty::PredicateKind::Ambiguous => {}
267 ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
268 self.add_alias_term(alias);
269 self.add_term(term);
270 }
271 ty::PredicateKind::AliasRelate(t1, t2, _) => {
272 self.add_term(t1);
273 self.add_term(t2);
274 }
275 }
276 }
277
278 fn add_ty(&mut self, ty: Ty<'_>) {
279 self.add_flags(ty.flags());
280 self.add_exclusive_binder(ty.outer_exclusive_binder());
281 }
282
283 fn add_tys(&mut self, tys: &[Ty<'_>]) {
284 for &ty in tys {
285 self.add_ty(ty);
286 }
287 }
288
289 fn add_region(&mut self, r: ty::Region<'_>) {
290 self.add_flags(r.type_flags());
291 if let ty::ReBound(debruijn, _) = *r {
292 self.add_bound_var(debruijn);
293 }
294 }
295
296 fn add_const(&mut self, c: ty::Const<'_>) {
297 self.add_flags(c.flags());
298 self.add_exclusive_binder(c.outer_exclusive_binder());
299 }
300
301 fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) {
302 match *c {
303 ty::ConstKind::Unevaluated(uv) => {
304 self.add_args(uv.args);
305 self.add_flags(TypeFlags::HAS_CT_PROJECTION);
306 }
307 ty::ConstKind::Infer(infer) => match infer {
308 InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
309 InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
310 },
311 ty::ConstKind::Bound(debruijn, _) => {
312 self.add_bound_var(debruijn);
313 self.add_flags(TypeFlags::HAS_CT_BOUND);
314 }
315 ty::ConstKind::Param(_) => {
316 self.add_flags(TypeFlags::HAS_CT_PARAM);
317 }
318 ty::ConstKind::Placeholder(_) => {
319 self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
320 }
321 ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
322 ty::ConstKind::Expr(e) => self.add_args(e.args()),
323 ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
324 }
325 }
326
327 fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
328 self.add_args(projection.args);
329 match projection.term.unpack() {
330 ty::TermKind::Ty(ty) => self.add_ty(ty),
331 ty::TermKind::Const(ct) => self.add_const(ct),
332 }
333 }
334
335 fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) {
336 self.add_args(alias_ty.args);
337 }
338
339 fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) {
340 self.add_args(alias_term.args);
341 }
342
343 fn add_args(&mut self, args: &[GenericArg<'_>]) {
344 for kind in args {
345 match kind.unpack() {
346 GenericArgKind::Type(ty) => self.add_ty(ty),
347 GenericArgKind::Lifetime(lt) => self.add_region(lt),
348 GenericArgKind::Const(ct) => self.add_const(ct),
349 }
350 }
351 }
352
353 fn add_term(&mut self, term: ty::Term<'_>) {
354 match term.unpack() {
355 ty::TermKind::Ty(ty) => self.add_ty(ty),
356 ty::TermKind::Const(ct) => self.add_const(ct),
357 }
358 }
359}