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