]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_middle/src/mir/type_foldable.rs
Refactor how SwitchInt stores jump targets
[rust.git] / compiler / rustc_middle / src / mir / type_foldable.rs
1 //! `TypeFoldable` implementations for MIR types
2
3 use super::*;
4 use crate::ty;
5
6 CloneTypeFoldableAndLiftImpls! {
7     BlockTailInfo,
8     MirPhase,
9     SourceInfo,
10     FakeReadCause,
11     RetagKind,
12     SourceScope,
13     SourceScopeData,
14     SourceScopeLocalData,
15     UserTypeAnnotationIndex,
16 }
17
18 impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> {
19     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
20         use crate::mir::TerminatorKind::*;
21
22         let kind = match self.kind {
23             Goto { target } => Goto { target },
24             SwitchInt { ref discr, switch_ty, ref targets } => SwitchInt {
25                 discr: discr.fold_with(folder),
26                 switch_ty: switch_ty.fold_with(folder),
27                 targets: targets.clone(),
28             },
29             Drop { ref place, target, unwind } => {
30                 Drop { place: place.fold_with(folder), target, unwind }
31             }
32             DropAndReplace { ref place, ref value, target, unwind } => DropAndReplace {
33                 place: place.fold_with(folder),
34                 value: value.fold_with(folder),
35                 target,
36                 unwind,
37             },
38             Yield { ref value, resume, ref resume_arg, drop } => Yield {
39                 value: value.fold_with(folder),
40                 resume,
41                 resume_arg: resume_arg.fold_with(folder),
42                 drop,
43             },
44             Call { ref func, ref args, ref destination, cleanup, from_hir_call, fn_span } => {
45                 let dest =
46                     destination.as_ref().map(|&(ref loc, dest)| (loc.fold_with(folder), dest));
47
48                 Call {
49                     func: func.fold_with(folder),
50                     args: args.fold_with(folder),
51                     destination: dest,
52                     cleanup,
53                     from_hir_call,
54                     fn_span,
55                 }
56             }
57             Assert { ref cond, expected, ref msg, target, cleanup } => {
58                 use AssertKind::*;
59                 let msg = match msg {
60                     BoundsCheck { len, index } => {
61                         BoundsCheck { len: len.fold_with(folder), index: index.fold_with(folder) }
62                     }
63                     Overflow(op, l, r) => Overflow(*op, l.fold_with(folder), r.fold_with(folder)),
64                     OverflowNeg(op) => OverflowNeg(op.fold_with(folder)),
65                     DivisionByZero(op) => DivisionByZero(op.fold_with(folder)),
66                     RemainderByZero(op) => RemainderByZero(op.fold_with(folder)),
67                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => msg.clone(),
68                 };
69                 Assert { cond: cond.fold_with(folder), expected, msg, target, cleanup }
70             }
71             GeneratorDrop => GeneratorDrop,
72             Resume => Resume,
73             Abort => Abort,
74             Return => Return,
75             Unreachable => Unreachable,
76             FalseEdge { real_target, imaginary_target } => {
77                 FalseEdge { real_target, imaginary_target }
78             }
79             FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind },
80             InlineAsm { template, ref operands, options, line_spans, destination } => InlineAsm {
81                 template,
82                 operands: operands.fold_with(folder),
83                 options,
84                 line_spans,
85                 destination,
86             },
87         };
88         Terminator { source_info: self.source_info, kind }
89     }
90
91     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
92         use crate::mir::TerminatorKind::*;
93
94         match self.kind {
95             SwitchInt { ref discr, switch_ty, .. } => {
96                 discr.visit_with(visitor) || switch_ty.visit_with(visitor)
97             }
98             Drop { ref place, .. } => place.visit_with(visitor),
99             DropAndReplace { ref place, ref value, .. } => {
100                 place.visit_with(visitor) || value.visit_with(visitor)
101             }
102             Yield { ref value, .. } => value.visit_with(visitor),
103             Call { ref func, ref args, ref destination, .. } => {
104                 let dest = if let Some((ref loc, _)) = *destination {
105                     loc.visit_with(visitor)
106                 } else {
107                     false
108                 };
109                 dest || func.visit_with(visitor) || args.visit_with(visitor)
110             }
111             Assert { ref cond, ref msg, .. } => {
112                 if cond.visit_with(visitor) {
113                     use AssertKind::*;
114                     match msg {
115                         BoundsCheck { ref len, ref index } => {
116                             len.visit_with(visitor) || index.visit_with(visitor)
117                         }
118                         Overflow(_, l, r) => l.visit_with(visitor) || r.visit_with(visitor),
119                         OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
120                             op.visit_with(visitor)
121                         }
122                         ResumedAfterReturn(_) | ResumedAfterPanic(_) => false,
123                     }
124                 } else {
125                     false
126                 }
127             }
128             InlineAsm { ref operands, .. } => operands.visit_with(visitor),
129             Goto { .. }
130             | Resume
131             | Abort
132             | Return
133             | GeneratorDrop
134             | Unreachable
135             | FalseEdge { .. }
136             | FalseUnwind { .. } => false,
137         }
138     }
139 }
140
141 impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {
142     fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
143         *self
144     }
145
146     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
147         false
148     }
149 }
150
151 impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
152     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
153         Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
154     }
155
156     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
157         self.local.visit_with(visitor) || self.projection.visit_with(visitor)
158     }
159 }
160
161 impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
162     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
163         let v = self.iter().map(|t| t.fold_with(folder)).collect::<Vec<_>>();
164         folder.tcx().intern_place_elems(&v)
165     }
166
167     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
168         self.iter().any(|t| t.visit_with(visitor))
169     }
170 }
171
172 impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
173     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
174         use crate::mir::Rvalue::*;
175         match *self {
176             Use(ref op) => Use(op.fold_with(folder)),
177             Repeat(ref op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)),
178             ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)),
179             Ref(region, bk, ref place) => {
180                 Ref(region.fold_with(folder), bk, place.fold_with(folder))
181             }
182             AddressOf(mutability, ref place) => AddressOf(mutability, place.fold_with(folder)),
183             Len(ref place) => Len(place.fold_with(folder)),
184             Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)),
185             BinaryOp(op, ref rhs, ref lhs) => {
186                 BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
187             }
188             CheckedBinaryOp(op, ref rhs, ref lhs) => {
189                 CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder))
190             }
191             UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)),
192             Discriminant(ref place) => Discriminant(place.fold_with(folder)),
193             NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)),
194             Aggregate(ref kind, ref fields) => {
195                 let kind = box match **kind {
196                     AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)),
197                     AggregateKind::Tuple => AggregateKind::Tuple,
198                     AggregateKind::Adt(def, v, substs, user_ty, n) => AggregateKind::Adt(
199                         def,
200                         v,
201                         substs.fold_with(folder),
202                         user_ty.fold_with(folder),
203                         n,
204                     ),
205                     AggregateKind::Closure(id, substs) => {
206                         AggregateKind::Closure(id, substs.fold_with(folder))
207                     }
208                     AggregateKind::Generator(id, substs, movablity) => {
209                         AggregateKind::Generator(id, substs.fold_with(folder), movablity)
210                     }
211                 };
212                 Aggregate(kind, fields.fold_with(folder))
213             }
214         }
215     }
216
217     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
218         use crate::mir::Rvalue::*;
219         match *self {
220             Use(ref op) => op.visit_with(visitor),
221             Repeat(ref op, _) => op.visit_with(visitor),
222             ThreadLocalRef(did) => did.visit_with(visitor),
223             Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor),
224             AddressOf(_, ref place) => place.visit_with(visitor),
225             Len(ref place) => place.visit_with(visitor),
226             Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor),
227             BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => {
228                 rhs.visit_with(visitor) || lhs.visit_with(visitor)
229             }
230             UnaryOp(_, ref val) => val.visit_with(visitor),
231             Discriminant(ref place) => place.visit_with(visitor),
232             NullaryOp(_, ty) => ty.visit_with(visitor),
233             Aggregate(ref kind, ref fields) => {
234                 (match **kind {
235                     AggregateKind::Array(ty) => ty.visit_with(visitor),
236                     AggregateKind::Tuple => false,
237                     AggregateKind::Adt(_, _, substs, user_ty, _) => {
238                         substs.visit_with(visitor) || user_ty.visit_with(visitor)
239                     }
240                     AggregateKind::Closure(_, substs) => substs.visit_with(visitor),
241                     AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor),
242                 }) || fields.visit_with(visitor)
243             }
244         }
245     }
246 }
247
248 impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> {
249     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
250         match *self {
251             Operand::Copy(ref place) => Operand::Copy(place.fold_with(folder)),
252             Operand::Move(ref place) => Operand::Move(place.fold_with(folder)),
253             Operand::Constant(ref c) => Operand::Constant(c.fold_with(folder)),
254         }
255     }
256
257     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
258         match *self {
259             Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor),
260             Operand::Constant(ref c) => c.visit_with(visitor),
261         }
262     }
263 }
264
265 impl<'tcx> TypeFoldable<'tcx> for PlaceElem<'tcx> {
266     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
267         use crate::mir::ProjectionElem::*;
268
269         match *self {
270             Deref => Deref,
271             Field(f, ty) => Field(f, ty.fold_with(folder)),
272             Index(v) => Index(v.fold_with(folder)),
273             Downcast(symbol, variantidx) => Downcast(symbol, variantidx),
274             ConstantIndex { offset, min_length, from_end } => {
275                 ConstantIndex { offset, min_length, from_end }
276             }
277             Subslice { from, to, from_end } => Subslice { from, to, from_end },
278         }
279     }
280
281     fn super_visit_with<Vs: TypeVisitor<'tcx>>(&self, visitor: &mut Vs) -> bool {
282         use crate::mir::ProjectionElem::*;
283
284         match self {
285             Field(_, ty) => ty.visit_with(visitor),
286             Index(v) => v.visit_with(visitor),
287             _ => false,
288         }
289     }
290 }
291
292 impl<'tcx> TypeFoldable<'tcx> for Field {
293     fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
294         *self
295     }
296     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
297         false
298     }
299 }
300
301 impl<'tcx> TypeFoldable<'tcx> for GeneratorSavedLocal {
302     fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
303         *self
304     }
305     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
306         false
307     }
308 }
309
310 impl<'tcx, R: Idx, C: Idx> TypeFoldable<'tcx> for BitMatrix<R, C> {
311     fn super_fold_with<F: TypeFolder<'tcx>>(&self, _: &mut F) -> Self {
312         self.clone()
313     }
314     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _: &mut V) -> bool {
315         false
316     }
317 }
318
319 impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> {
320     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
321         Constant {
322             span: self.span,
323             user_ty: self.user_ty.fold_with(folder),
324             literal: self.literal.fold_with(folder),
325         }
326     }
327     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
328         self.literal.visit_with(visitor)
329     }
330 }