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 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
105 }
106
107 ty::Coroutine(_, args) => {
108 let args = args.as_coroutine();
109 let should_remove_further_specializable =
110 !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
111 self.add_args(args.parent_args());
112 if should_remove_further_specializable {
113 self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
114 }
115
116 self.add_ty(args.resume_ty());
117 self.add_ty(args.return_ty());
118 self.add_ty(args.witness());
119 self.add_ty(args.yield_ty());
120 self.add_ty(args.tupled_upvars_ty());
121 }
122
123 ty::CoroutineWitness(_, args) => {
124 let should_remove_further_specializable =
125 !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
126 self.add_args(args);
127 if should_remove_further_specializable {
128 self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
129 }
130 self.add_flags(TypeFlags::HAS_TY_COROUTINE);
131 }
132
133 &ty::Closure(_, args) => {
134 let args = args.as_closure();
135 let should_remove_further_specializable =
136 !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
137 self.add_args(args.parent_args());
138 if should_remove_further_specializable {
139 self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
140 }
141
142 self.add_ty(args.sig_as_fn_ptr_ty());
143 self.add_ty(args.kind_ty());
144 self.add_ty(args.tupled_upvars_ty());
145 }
146
147 &ty::CoroutineClosure(_, args) => {
148 let args = args.as_coroutine_closure();
149 let should_remove_further_specializable =
150 !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
151 self.add_args(args.parent_args());
152 if should_remove_further_specializable {
153 self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
154 }
155
156 self.add_ty(args.kind_ty());
157 self.add_ty(args.signature_parts_ty());
158 self.add_ty(args.tupled_upvars_ty());
159 self.add_ty(args.coroutine_captures_by_ref_ty());
160 self.add_ty(args.coroutine_witness_ty());
161 }
162
163 &ty::Bound(debruijn, _) => {
164 self.add_bound_var(debruijn);
165 self.add_flags(TypeFlags::HAS_TY_BOUND);
166 }
167
168 &ty::Placeholder(..) => {
169 self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
170 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
171 }
172
173 &ty::Infer(infer) => {
174 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
175 match infer {
176 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
177 self.add_flags(TypeFlags::HAS_TY_FRESH)
178 }
179
180 ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
181 self.add_flags(TypeFlags::HAS_TY_INFER)
182 }
183 }
184 }
185
186 &ty::Adt(_, args) => {
187 self.add_args(args);
188 }
189
190 &ty::Alias(kind, data) => {
191 self.add_flags(match kind {
192 ty::Projection => TypeFlags::HAS_TY_PROJECTION,
193 ty::Weak => TypeFlags::HAS_TY_WEAK,
194 ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
195 ty::Inherent => TypeFlags::HAS_TY_INHERENT,
196 });
197
198 self.add_alias_ty(data);
199 }
200
201 &ty::Dynamic(obj, r, _) => {
202 for predicate in obj.iter() {
203 self.bound_computation(predicate, |computation, predicate| match predicate {
204 ty::ExistentialPredicate::Trait(tr) => computation.add_args(tr.args),
205 ty::ExistentialPredicate::Projection(p) => {
206 computation.add_existential_projection(&p);
207 }
208 ty::ExistentialPredicate::AutoTrait(_) => {}
209 });
210 }
211
212 self.add_region(r);
213 }
214
215 &ty::Array(tt, len) => {
216 self.add_ty(tt);
217 self.add_const(len);
218 }
219
220 &ty::Pat(ty, pat) => {
221 self.add_ty(ty);
222 match *pat {
223 ty::PatternKind::Range { start, end, include_end: _ } => {
224 if let Some(start) = start {
225 self.add_const(start)
226 }
227 if let Some(end) = end {
228 self.add_const(end)
229 }
230 }
231 }
232 }
233
234 &ty::Slice(tt) => self.add_ty(tt),
235
236 &ty::RawPtr(ty, _) => {
237 self.add_ty(ty);
238 }
239
240 &ty::Ref(r, ty, _) => {
241 self.add_region(r);
242 self.add_ty(ty);
243 }
244
245 &ty::Tuple(types) => {
246 self.add_tys(types);
247 }
248
249 &ty::FnDef(_, args) => {
250 self.add_args(args);
251 }
252
253 &ty::FnPtr(sig_tys, _) => self.bound_computation(sig_tys, |computation, sig_tys| {
254 computation.add_tys(sig_tys.inputs_and_output);
255 }),
256
257 &ty::UnsafeBinder(bound_ty) => {
258 self.bound_computation(bound_ty.into(), |computation, ty| {
259 computation.add_ty(ty);
260 })
261 }
262 }
263 }
264
265 fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
266 self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
267 }
268
269 fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
270 match atom {
271 ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_pred)) => {
272 self.add_args(trait_pred.trait_ref.args);
273 }
274 ty::PredicateKind::Clause(ty::ClauseKind::HostEffect(ty::HostEffectPredicate {
275 trait_ref,
276 constness: _,
277 })) => {
278 self.add_args(trait_ref.args);
279 }
280 ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
281 a,
282 b,
283 ))) => {
284 self.add_region(a);
285 self.add_region(b);
286 }
287 ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(
288 ty,
289 region,
290 ))) => {
291 self.add_ty(ty);
292 self.add_region(region);
293 }
294 ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
295 self.add_const(ct);
296 self.add_ty(ty);
297 }
298 ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
299 self.add_ty(a);
300 self.add_ty(b);
301 }
302 ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
303 self.add_ty(a);
304 self.add_ty(b);
305 }
306 ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
307 projection_term,
308 term,
309 })) => {
310 self.add_alias_term(projection_term);
311 self.add_term(term);
312 }
313 ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
314 self.add_args(slice::from_ref(&arg));
315 }
316 ty::PredicateKind::DynCompatible(_def_id) => {}
317 ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(uv)) => {
318 self.add_const(uv);
319 }
320 ty::PredicateKind::ConstEquate(expected, found) => {
321 self.add_const(expected);
322 self.add_const(found);
323 }
324 ty::PredicateKind::Ambiguous => {}
325 ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
326 self.add_alias_term(alias);
327 self.add_term(term);
328 }
329 ty::PredicateKind::AliasRelate(t1, t2, _) => {
330 self.add_term(t1);
331 self.add_term(t2);
332 }
333 }
334 }
335
336 fn add_ty(&mut self, ty: Ty<'_>) {
337 self.add_flags(ty.flags());
338 self.add_exclusive_binder(ty.outer_exclusive_binder());
339 }
340
341 fn add_tys(&mut self, tys: &[Ty<'_>]) {
342 for &ty in tys {
343 self.add_ty(ty);
344 }
345 }
346
347 fn add_region(&mut self, r: ty::Region<'_>) {
348 self.add_flags(r.type_flags());
349 if let ty::ReBound(debruijn, _) = *r {
350 self.add_bound_var(debruijn);
351 }
352 }
353
354 fn add_const(&mut self, c: ty::Const<'_>) {
355 self.add_flags(c.flags());
356 self.add_exclusive_binder(c.outer_exclusive_binder());
357 }
358
359 fn add_const_kind(&mut self, c: &ty::ConstKind<'_>) {
360 match *c {
361 ty::ConstKind::Unevaluated(uv) => {
362 self.add_args(uv.args);
363 self.add_flags(TypeFlags::HAS_CT_PROJECTION);
364 }
365 ty::ConstKind::Infer(infer) => {
366 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
367 match infer {
368 InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
369 InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
370 }
371 }
372 ty::ConstKind::Bound(debruijn, _) => {
373 self.add_bound_var(debruijn);
374 self.add_flags(TypeFlags::HAS_CT_BOUND);
375 }
376 ty::ConstKind::Param(_) => {
377 self.add_flags(TypeFlags::HAS_CT_PARAM);
378 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
379 }
380 ty::ConstKind::Placeholder(_) => {
381 self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
382 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
383 }
384 ty::ConstKind::Value(cv) => self.add_ty(cv.ty),
385 ty::ConstKind::Expr(e) => self.add_args(e.args()),
386 ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
387 }
388 }
389
390 fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
391 self.add_args(projection.args);
392 match projection.term.unpack() {
393 ty::TermKind::Ty(ty) => self.add_ty(ty),
394 ty::TermKind::Const(ct) => self.add_const(ct),
395 }
396 }
397
398 fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) {
399 self.add_args(alias_ty.args);
400 }
401
402 fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) {
403 self.add_args(alias_term.args);
404 }
405
406 fn add_args(&mut self, args: &[GenericArg<'_>]) {
407 for kind in args {
408 match kind.unpack() {
409 GenericArgKind::Type(ty) => self.add_ty(ty),
410 GenericArgKind::Lifetime(lt) => self.add_region(lt),
411 GenericArgKind::Const(ct) => self.add_const(ct),
412 }
413 }
414 }
415
416 fn add_term(&mut self, term: ty::Term<'_>) {
417 match term.unpack() {
418 ty::TermKind::Ty(ty) => self.add_ty(ty),
419 ty::TermKind::Const(ct) => self.add_const(ct),
420 }
421 }
422}