]> git.lizzy.rs Git - rust.git/blob - src/librustc/ty/flags.rs
Rollup merge of #58908 - JohnTitor:improve-rand, r=scottmcm
[rust.git] / src / librustc / ty / flags.rs
1 use crate::ty::subst::{SubstsRef, UnpackedKind};
2 use crate::ty::{self, Ty, TypeFlags, TypeFoldable, InferConst};
3 use crate::mir::interpret::ConstValue;
4
5 #[derive(Debug)]
6 pub struct FlagComputation {
7     pub flags: TypeFlags,
8
9     // see `TyS::outer_exclusive_binder` for details
10     pub outer_exclusive_binder: ty::DebruijnIndex,
11 }
12
13 impl FlagComputation {
14     fn new() -> FlagComputation {
15         FlagComputation {
16             flags: TypeFlags::empty(),
17             outer_exclusive_binder: ty::INNERMOST,
18         }
19     }
20
21     pub fn for_sty(st: &ty::TyKind<'_>) -> FlagComputation {
22         let mut result = FlagComputation::new();
23         result.add_sty(st);
24         result
25     }
26
27     fn add_flags(&mut self, flags: TypeFlags) {
28         self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS);
29     }
30
31     /// indicates that `self` refers to something at binding level `binder`
32     fn add_binder(&mut self, binder: ty::DebruijnIndex) {
33         let exclusive_binder = binder.shifted_in(1);
34         self.add_exclusive_binder(exclusive_binder);
35     }
36
37     /// indicates that `self` refers to something *inside* binding
38     /// level `binder` -- not bound by `binder`, but bound by the next
39     /// binder internal to it
40     fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) {
41         self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder);
42     }
43
44     /// Adds the flags/depth from a set of types that appear within the current type, but within a
45     /// region binder.
46     fn add_bound_computation(&mut self, computation: &FlagComputation) {
47         self.add_flags(computation.flags);
48
49         // The types that contributed to `computation` occurred within
50         // a region binder, so subtract one from the region depth
51         // within when adding the depth to `self`.
52         let outer_exclusive_binder = computation.outer_exclusive_binder;
53         if outer_exclusive_binder > ty::INNERMOST {
54             self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1));
55         } // otherwise, this binder captures nothing
56     }
57
58     fn add_sty(&mut self, st: &ty::TyKind<'_>) {
59         match st {
60             &ty::Bool |
61             &ty::Char |
62             &ty::Int(_) |
63             &ty::Float(_) |
64             &ty::Uint(_) |
65             &ty::Never |
66             &ty::Str |
67             &ty::Foreign(..) => {
68             }
69
70             // You might think that we could just return Error for
71             // any type containing Error as a component, and get
72             // rid of the TypeFlags::HAS_TY_ERR flag -- likewise for ty_bot (with
73             // the exception of function types that return bot).
74             // But doing so caused sporadic memory corruption, and
75             // neither I (tjc) nor nmatsakis could figure out why,
76             // so we're doing it this way.
77             &ty::Error => {
78                 self.add_flags(TypeFlags::HAS_TY_ERR)
79             }
80
81             &ty::Param(ref p) => {
82                 self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
83                 if p.is_self() {
84                     self.add_flags(TypeFlags::HAS_SELF);
85                 } else {
86                     self.add_flags(TypeFlags::HAS_PARAMS);
87                 }
88             }
89
90             &ty::Generator(_, ref substs, _) => {
91                 self.add_flags(TypeFlags::HAS_TY_CLOSURE);
92                 self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
93                 self.add_substs(&substs.substs);
94             }
95
96             &ty::GeneratorWitness(ref ts) => {
97                 let mut computation = FlagComputation::new();
98                 computation.add_tys(&ts.skip_binder()[..]);
99                 self.add_bound_computation(&computation);
100             }
101
102             &ty::Closure(_, ref substs) => {
103                 self.add_flags(TypeFlags::HAS_TY_CLOSURE);
104                 self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES);
105                 self.add_substs(&substs.substs);
106             }
107
108             &ty::Bound(debruijn, _) => {
109                 self.add_binder(debruijn);
110             }
111
112             &ty::Placeholder(..) => {
113                 self.add_flags(TypeFlags::HAS_TY_PLACEHOLDER);
114             }
115
116             &ty::Infer(infer) => {
117                 self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right?
118                 self.add_flags(TypeFlags::HAS_TY_INFER);
119                 match infer {
120                     ty::FreshTy(_) |
121                     ty::FreshIntTy(_) |
122                     ty::FreshFloatTy(_) => {
123                     }
124
125                     ty::TyVar(_) |
126                     ty::IntVar(_) |
127                     ty::FloatVar(_) => {
128                         self.add_flags(TypeFlags::KEEP_IN_LOCAL_TCX)
129                     }
130                 }
131             }
132
133             &ty::Adt(_, substs) => {
134                 self.add_substs(substs);
135             }
136
137             &ty::Projection(ref data) => {
138                 // currently we can't normalize projections that
139                 // include bound regions, so track those separately.
140                 if !data.has_escaping_bound_vars() {
141                     self.add_flags(TypeFlags::HAS_NORMALIZABLE_PROJECTION);
142                 }
143                 self.add_flags(TypeFlags::HAS_PROJECTION);
144                 self.add_projection_ty(data);
145             }
146
147             &ty::UnnormalizedProjection(ref data) => {
148                 self.add_flags(TypeFlags::HAS_PROJECTION);
149                 self.add_projection_ty(data);
150             },
151
152             &ty::Opaque(_, substs) => {
153                 self.add_flags(TypeFlags::HAS_PROJECTION);
154                 self.add_substs(substs);
155             }
156
157             &ty::Dynamic(ref obj, r) => {
158                 let mut computation = FlagComputation::new();
159                 for predicate in obj.skip_binder().iter() {
160                     match *predicate {
161                         ty::ExistentialPredicate::Trait(tr) => computation.add_substs(tr.substs),
162                         ty::ExistentialPredicate::Projection(p) => {
163                             let mut proj_computation = FlagComputation::new();
164                             proj_computation.add_existential_projection(&p);
165                             self.add_bound_computation(&proj_computation);
166                         }
167                         ty::ExistentialPredicate::AutoTrait(_) => {}
168                     }
169                 }
170                 self.add_bound_computation(&computation);
171                 self.add_region(r);
172             }
173
174             &ty::Array(tt, len) => {
175                 self.add_ty(tt);
176                 if let ty::LazyConst::Unevaluated(_, substs) = len {
177                     self.add_flags(TypeFlags::HAS_PROJECTION);
178                     self.add_substs(substs);
179                 }
180             }
181
182             &ty::Slice(tt) => {
183                 self.add_ty(tt)
184             }
185
186             &ty::RawPtr(ref m) => {
187                 self.add_ty(m.ty);
188             }
189
190             &ty::Ref(r, ty, _) => {
191                 self.add_region(r);
192                 self.add_ty(ty);
193             }
194
195             &ty::Tuple(ref ts) => {
196                 self.add_tys(&ts[..]);
197             }
198
199             &ty::FnDef(_, substs) => {
200                 self.add_substs(substs);
201             }
202
203             &ty::FnPtr(f) => {
204                 self.add_fn_sig(f);
205             }
206         }
207     }
208
209     fn add_ty(&mut self, ty: Ty<'_>) {
210         self.add_flags(ty.flags);
211         self.add_exclusive_binder(ty.outer_exclusive_binder);
212     }
213
214     fn add_tys(&mut self, tys: &[Ty<'_>]) {
215         for &ty in tys {
216             self.add_ty(ty);
217         }
218     }
219
220     fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig<'_>) {
221         let mut computation = FlagComputation::new();
222
223         computation.add_tys(fn_sig.skip_binder().inputs());
224         computation.add_ty(fn_sig.skip_binder().output());
225
226         self.add_bound_computation(&computation);
227     }
228
229     fn add_region(&mut self, r: ty::Region<'_>) {
230         self.add_flags(r.type_flags());
231         if let ty::ReLateBound(debruijn, _) = *r {
232             self.add_binder(debruijn);
233         }
234     }
235
236     fn add_const(&mut self, c: &ty::LazyConst<'_>) {
237         match c {
238             ty::LazyConst::Unevaluated(_, substs) => self.add_substs(substs),
239             // Only done to add the binder for the type. The type flags are
240             // included in `Const::type_flags`.
241             ty::LazyConst::Evaluated(ty::Const { ty, val }) => {
242                 self.add_ty(ty);
243                 if let ConstValue::Infer(InferConst::Canonical(debruijn, _)) = val {
244                     self.add_binder(*debruijn)
245                 }
246             }
247         }
248         self.add_flags(c.type_flags());
249     }
250
251     fn add_existential_projection(&mut self, projection: &ty::ExistentialProjection<'_>) {
252         self.add_substs(projection.substs);
253         self.add_ty(projection.ty);
254     }
255
256     fn add_projection_ty(&mut self, projection_ty: &ty::ProjectionTy<'_>) {
257         self.add_substs(projection_ty.substs);
258     }
259
260     fn add_substs(&mut self, substs: SubstsRef<'_>) {
261         for kind in substs {
262             match kind.unpack() {
263                 UnpackedKind::Type(ty) => self.add_ty(ty),
264                 UnpackedKind::Lifetime(lt) => self.add_region(lt),
265                 UnpackedKind::Const(ct) => self.add_const(ct),
266             }
267         }
268     }
269 }