]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/ty/flags.rs
Add type flags support for Ty and Const late-bound regions
[rust.git] / compiler / rustc_middle / src / ty / flags.rs
1 use crate::ty::subst::{GenericArg, GenericArgKind};
2 use crate::ty::{self, InferConst, Ty, TypeFlags};
3 use std::slice;
4
5 #[derive(Debug)]
6 pub struct FlagComputation {
7     pub flags: TypeFlags,
8
9     /// see `Ty::outer_exclusive_binder` for details
10     pub outer_exclusive_binder: ty::DebruijnIndex,
11 }
12
13 impl 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(c: ty::Const<'_>) -> TypeFlags {
32         let mut result = FlagComputation::new();
33         result.add_const(c);
34         result.flags
35     }
36
37     fn add_flags(&mut self, flags: TypeFlags) {
38         self.flags = self.flags | flags;
39     }
40
41     /// indicates that `self` refers to something at binding level `binder`
42     fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
43         let exclusive_binder = binder.shifted_in(1);
44         self.add_exclusive_binder(exclusive_binder);
45     }
46
47     /// indicates that `self` refers to something *inside* binding
48     /// level `binder` -- not bound by `binder`, but bound by the next
49     /// binder internal to it
50     fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
51         self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
52     }
53
54     /// Adds the flags/depth from a set of types that appear within the current type, but within a
55     /// region binder.
56     fn bound_computation<T, F>(&mut self, value: ty::Binder<'_, T>, f: F)
57     where
58         F: FnOnce(&mut Self, T),
59     {
60         let mut computation = FlagComputation::new();
61
62         for bv in value.bound_vars() {
63             match bv {
64                 ty::BoundVariableKind::Ty(_) => {
65                     computation.flags |= TypeFlags::HAS_TY_LATE_BOUND;
66                 }
67                 ty::BoundVariableKind::Region(_) => {
68                     computation.flags |= TypeFlags::HAS_RE_LATE_BOUND;
69                 }
70                 ty::BoundVariableKind::Const => {
71                     computation.flags |= TypeFlags::HAS_CT_LATE_BOUND;
72                 }
73             }
74         }
75
76         f(&mut computation, value.skip_binder());
77
78         self.add_flags(computation.flags);
79
80         // The types that contributed to `computation` occurred within
81         // a region binder, so subtract one from the region depth
82         // within when adding the depth to `self`.
83         let outer_exclusive_binder = computation.outer_exclusive_binder;
84         if outer_exclusive_binder > ty::INNERMOST {
85             self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
86         } // otherwise, this binder captures nothing
87     }
88
89     #[allow(rustc::usage_of_ty_tykind)]
90     fn add_kind(&mut self, kind: &ty::TyKind<'_>) {
91         match kind {
92             &ty::Bool
93             | &ty::Char
94             | &ty::Int(_)
95             | &ty::Float(_)
96             | &ty::Uint(_)
97             | &ty::Never
98             | &ty::Str
99             | &ty::Foreign(..) => {}
100
101             &ty::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
102
103             &ty::Param(_) => {
104                 self.add_flags(TypeFlags::HAS_TY_PARAM);
105                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
106             }
107
108             ty::Generator(_, substs, _) => {
109                 let substs = substs.as_generator();
110                 let should_remove_further_specializable =
111                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
112                 self.add_substs(substs.parent_substs());
113                 if should_remove_further_specializable {
114                     self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
115                 }
116
117                 self.add_ty(substs.resume_ty());
118                 self.add_ty(substs.return_ty());
119                 self.add_ty(substs.witness());
120                 self.add_ty(substs.yield_ty());
121                 self.add_ty(substs.tupled_upvars_ty());
122             }
123
124             &ty::GeneratorWitness(ts) => {
125                 self.bound_computation(ts, |flags, ts| flags.add_tys(ts));
126             }
127
128             &ty::Closure(_, substs) => {
129                 let substs = substs.as_closure();
130                 let should_remove_further_specializable =
131                     !self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
132                 self.add_substs(substs.parent_substs());
133                 if should_remove_further_specializable {
134                     self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
135                 }
136
137                 self.add_ty(substs.sig_as_fn_ptr_ty());
138                 self.add_ty(substs.kind_ty());
139                 self.add_ty(substs.tupled_upvars_ty());
140             }
141
142             &ty::Bound(debruijn, _) => {
143                 self.add_bound_var(debruijn);
144                 self.add_flags(TypeFlags::HAS_TY_LATE_BOUND);
145             }
146
147             &ty::Placeholder(..) => {
148                 self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
149                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
150             }
151
152             &ty::Infer(infer) => {
153                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
154                 match infer {
155                     ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
156                         self.add_flags(TypeFlags::HAS_TY_FRESH)
157                     }
158
159                     ty::TyVar(_) | ty::IntVar(_) | ty::FloatVar(_) => {
160                         self.add_flags(TypeFlags::HAS_TY_INFER)
161                     }
162                 }
163             }
164
165             &ty::Adt(_, substs) => {
166                 self.add_substs(substs);
167             }
168
169             &ty::Alias(ty::Projection, data) => {
170                 self.add_flags(TypeFlags::HAS_TY_PROJECTION);
171                 self.add_projection_ty(data);
172             }
173
174             &ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
175                 self.add_flags(TypeFlags::HAS_TY_OPAQUE);
176                 self.add_substs(substs);
177             }
178
179             &ty::Dynamic(obj, r, _) => {
180                 for predicate in obj.iter() {
181                     self.bound_computation(predicate, |computation, predicate| match predicate {
182                         ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
183                         ty::ExistentialPredicate::Projection(p) => {
184                             computation.add_existential_projection(&p);
185                         }
186                         ty::ExistentialPredicate::AutoTrait(_) => {}
187                     });
188                 }
189
190                 self.add_region(r);
191             }
192
193             &ty::Array(tt, len) => {
194                 self.add_ty(tt);
195                 self.add_const(len);
196             }
197
198             &ty::Slice(tt) => self.add_ty(tt),
199
200             ty::RawPtr(m) => {
201                 self.add_ty(m.ty);
202             }
203
204             &ty::Ref(r, ty, _) => {
205                 self.add_region(r);
206                 self.add_ty(ty);
207             }
208
209             &ty::Tuple(types) => {
210                 self.add_tys(types);
211             }
212
213             &ty::FnDef(_, substs) => {
214                 self.add_substs(substs);
215             }
216
217             &ty::FnPtr(fn_sig) => self.bound_computation(fn_sig, |computation, fn_sig| {
218                 computation.add_tys(fn_sig.inputs());
219                 computation.add_ty(fn_sig.output());
220             }),
221         }
222     }
223
224     fn add_predicate(&mut self, binder: ty::Binder<'_, ty::PredicateKind<'_>>) {
225         self.bound_computation(binder, |computation, atom| computation.add_predicate_atom(atom));
226     }
227
228     fn add_predicate_atom(&mut self, atom: ty::PredicateKind<'_>) {
229         match atom {
230             ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) => {
231                 self.add_substs(trait_pred.trait_ref.substs);
232             }
233             ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(a, b))) => {
234                 self.add_region(a);
235                 self.add_region(b);
236             }
237             ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
238                 ty,
239                 region,
240             ))) => {
241                 self.add_ty(ty);
242                 self.add_region(region);
243             }
244             ty::PredicateKind::Subtype(ty::SubtypePredicate { a_is_expected: _, a, b }) => {
245                 self.add_ty(a);
246                 self.add_ty(b);
247             }
248             ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
249                 self.add_ty(a);
250                 self.add_ty(b);
251             }
252             ty::PredicateKind::Clause(ty::Clause::Projection(ty::ProjectionPredicate {
253                 projection_ty,
254                 term,
255             })) => {
256                 self.add_projection_ty(projection_ty);
257                 match term.unpack() {
258                     ty::TermKind::Ty(ty) => self.add_ty(ty),
259                     ty::TermKind::Const(c) => self.add_const(c),
260                 }
261             }
262             ty::PredicateKind::WellFormed(arg) => {
263                 self.add_substs(slice::from_ref(&arg));
264             }
265             ty::PredicateKind::ObjectSafe(_def_id) => {}
266             ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
267                 self.add_substs(substs);
268             }
269             ty::PredicateKind::ConstEvaluatable(uv) => {
270                 self.add_const(uv);
271             }
272             ty::PredicateKind::ConstEquate(expected, found) => {
273                 self.add_const(expected);
274                 self.add_const(found);
275             }
276             ty::PredicateKind::TypeWellFormedFromEnv(ty) => {
277                 self.add_ty(ty);
278             }
279             ty::PredicateKind::Ambiguous => {}
280         }
281     }
282
283     fn add_ty(&mut self, ty: Ty<'_>) {
284         self.add_flags(ty.flags());
285         self.add_exclusive_binder(ty.outer_exclusive_binder());
286     }
287
288     fn add_tys(&mut self, tys: &[Ty<'_>]) {
289         for &ty in tys {
290             self.add_ty(ty);
291         }
292     }
293
294     fn add_region(&mut self, r: ty::Region<'_>) {
295         self.add_flags(r.type_flags());
296         if let ty::ReLateBound(debruijn, _) = *r {
297             self.add_bound_var(debruijn);
298         }
299     }
300
301     fn add_const(&mut self, c: ty::Const<'_>) {
302         self.add_ty(c.ty());
303         match c.kind() {
304             ty::ConstKind::Unevaluated(uv) => {
305                 self.add_substs(uv.substs);
306                 self.add_flags(TypeFlags::HAS_CT_PROJECTION);
307             }
308             ty::ConstKind::Infer(infer) => {
309                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
310                 match infer {
311                     InferConst::Fresh(_) => self.add_flags(TypeFlags::HAS_CT_FRESH),
312                     InferConst::Var(_) => self.add_flags(TypeFlags::HAS_CT_INFER),
313                 }
314             }
315             ty::ConstKind::Bound(debruijn, _) => {
316                 self.add_bound_var(debruijn);
317                 self.add_flags(TypeFlags::HAS_CT_LATE_BOUND);
318             }
319             ty::ConstKind::Param(_) => {
320                 self.add_flags(TypeFlags::HAS_CT_PARAM);
321                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
322             }
323             ty::ConstKind::Placeholder(_) => {
324                 self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER);
325                 self.add_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
326             }
327             ty::ConstKind::Value(_) => {}
328             ty::ConstKind::Expr(e) => {
329                 use ty::Expr;
330                 match e {
331                     Expr::Binop(_, l, r) => {
332                         self.add_const(l);
333                         self.add_const(r);
334                     }
335                     Expr::UnOp(_, v) => self.add_const(v),
336                     Expr::FunctionCall(f, args) => {
337                         self.add_const(f);
338                         for arg in args {
339                             self.add_const(arg);
340                         }
341                     }
342                     Expr::Cast(_, c, t) => {
343                         self.add_ty(t);
344                         self.add_const(c);
345                     }
346                 }
347             }
348             ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR),
349         }
350     }
351
352     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
353         self.add_substs(projection.substs);
354         match projection.term.unpack() {
355             ty::TermKind::Ty(ty) => self.add_ty(ty),
356             ty::TermKind::Const(ct) => self.add_const(ct),
357         }
358     }
359
360     fn add_projection_ty(&mut self, projection_ty: ty::AliasTy<'_>) {
361         self.add_substs(projection_ty.substs);
362     }
363
364     fn add_substs(&mut self, substs: &[GenericArg<'_>]) {
365         for kind in substs {
366             match kind.unpack() {
367                 GenericArgKind::Type(ty) => self.add_ty(ty),
368                 GenericArgKind::Lifetime(lt) => self.add_region(lt),
369                 GenericArgKind::Const(ct) => self.add_const(ct),
370             }
371         }
372     }
373 }