]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/visit.rs
Rollup merge of #66570 - lzutao:stabilize-result-map_or, r=Dylan-DPC
[rust.git] / src / librustc / mir / visit.rs
1 use crate::ty::subst::SubstsRef;
2 use crate::ty::{CanonicalUserTypeAnnotation, Ty};
3 use crate::mir::*;
4 use syntax_pos::Span;
5
6 // # The MIR Visitor
7 //
8 // ## Overview
9 //
10 // There are two visitors, one for immutable and one for mutable references,
11 // but both are generated by the following macro. The code is written according
12 // to the following conventions:
13 //
14 // - introduce a `visit_foo` and a `super_foo` method for every MIR type
15 // - `visit_foo`, by default, calls `super_foo`
16 // - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
17 //
18 // This allows you as a user to override `visit_foo` for types are
19 // interested in, and invoke (within that method) call
20 // `self.super_foo` to get the default behavior. Just as in an OO
21 // language, you should never call `super` methods ordinarily except
22 // in that circumstance.
23 //
24 // For the most part, we do not destructure things external to the
25 // MIR, e.g., types, spans, etc, but simply visit them and stop. This
26 // avoids duplication with other visitors like `TypeFoldable`.
27 //
28 // ## Updating
29 //
30 // The code is written in a very deliberate style intended to minimize
31 // the chance of things being overlooked. You'll notice that we always
32 // use pattern matching to reference fields and we ensure that all
33 // matches are exhaustive.
34 //
35 // For example, the `super_basic_block_data` method begins like this:
36 //
37 // ```rust
38 // fn super_basic_block_data(&mut self,
39 //                           block: BasicBlock,
40 //                           data: & $($mutability)? BasicBlockData<'tcx>) {
41 //     let BasicBlockData {
42 //         statements,
43 //         terminator,
44 //         is_cleanup: _
45 //     } = *data;
46 //
47 //     for statement in statements {
48 //         self.visit_statement(block, statement);
49 //     }
50 //
51 //     ...
52 // }
53 // ```
54 //
55 // Here we used `let BasicBlockData { <fields> } = *data` deliberately,
56 // rather than writing `data.statements` in the body. This is because if one
57 // adds a new field to `BasicBlockData`, one will be forced to revise this code,
58 // and hence one will (hopefully) invoke the correct visit methods (if any).
59 //
60 // For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
61 // That means you never write `..` to skip over fields, nor do you write `_`
62 // to skip over variants in a `match`.
63 //
64 // The only place that `_` is acceptable is to match a field (or
65 // variant argument) that does not require visiting, as in
66 // `is_cleanup` above.
67
68 macro_rules! body_cache_type {
69     (mut $a:lifetime, $tcx:lifetime) => {
70         &mut BodyAndCache<$tcx>
71     };
72     ($a:lifetime, $tcx:lifetime) => {
73         ReadOnlyBodyAndCache<$a, $tcx>
74     };
75 }
76
77 macro_rules! make_mir_visitor {
78     ($visitor_trait_name:ident, $($mutability:ident)?) => {
79         pub trait $visitor_trait_name<'tcx> {
80             // Override these, and call `self.super_xxx` to revert back to the
81             // default behavior.
82
83             fn visit_body(
84                 &mut self,
85                 body: body_cache_type!($($mutability)? '_, 'tcx)
86             ) {
87                 self.super_body(body);
88             }
89
90             fn visit_basic_block_data(&mut self,
91                                       block: BasicBlock,
92                                       data: & $($mutability)? BasicBlockData<'tcx>) {
93                 self.super_basic_block_data(block, data);
94             }
95
96             fn visit_source_scope_data(&mut self,
97                                            scope_data: & $($mutability)? SourceScopeData) {
98                 self.super_source_scope_data(scope_data);
99             }
100
101             fn visit_statement(&mut self,
102                                statement: & $($mutability)? Statement<'tcx>,
103                                location: Location) {
104                 self.super_statement(statement, location);
105             }
106
107             fn visit_assign(&mut self,
108                             place: & $($mutability)? Place<'tcx>,
109                             rvalue: & $($mutability)? Rvalue<'tcx>,
110                             location: Location) {
111                 self.super_assign(place, rvalue, location);
112             }
113
114             fn visit_terminator(&mut self,
115                                 terminator: & $($mutability)? Terminator<'tcx>,
116                                 location: Location) {
117                 self.super_terminator(terminator, location);
118             }
119
120             fn visit_terminator_kind(&mut self,
121                                      kind: & $($mutability)? TerminatorKind<'tcx>,
122                                      location: Location) {
123                 self.super_terminator_kind(kind, location);
124             }
125
126             fn visit_assert_message(&mut self,
127                                     msg: & $($mutability)? AssertMessage<'tcx>,
128                                     location: Location) {
129                 self.super_assert_message(msg, location);
130             }
131
132             fn visit_rvalue(&mut self,
133                             rvalue: & $($mutability)? Rvalue<'tcx>,
134                             location: Location) {
135                 self.super_rvalue(rvalue, location);
136             }
137
138             fn visit_operand(&mut self,
139                              operand: & $($mutability)? Operand<'tcx>,
140                              location: Location) {
141                 self.super_operand(operand, location);
142             }
143
144             fn visit_ascribe_user_ty(&mut self,
145                                      place: & $($mutability)? Place<'tcx>,
146                                      variance: & $($mutability)? ty::Variance,
147                                      user_ty: & $($mutability)? UserTypeProjection,
148                                      location: Location) {
149                 self.super_ascribe_user_ty(place, variance, user_ty, location);
150             }
151
152             fn visit_retag(&mut self,
153                            kind: & $($mutability)? RetagKind,
154                            place: & $($mutability)? Place<'tcx>,
155                            location: Location) {
156                 self.super_retag(kind, place, location);
157             }
158
159             fn visit_place(&mut self,
160                             place: & $($mutability)? Place<'tcx>,
161                             context: PlaceContext,
162                             location: Location) {
163                 self.super_place(place, context, location);
164             }
165
166             fn visit_place_base(&mut self,
167                                 base: & $($mutability)? PlaceBase<'tcx>,
168                                 context: PlaceContext,
169                                 location: Location) {
170                 self.super_place_base(base, context, location);
171             }
172
173             visit_place_fns!($($mutability)?);
174
175             fn visit_constant(&mut self,
176                               constant: & $($mutability)? Constant<'tcx>,
177                               location: Location) {
178                 self.super_constant(constant, location);
179             }
180
181             fn visit_span(&mut self,
182                           span: & $($mutability)? Span) {
183                 self.super_span(span);
184             }
185
186             fn visit_source_info(&mut self,
187                                  source_info: & $($mutability)? SourceInfo) {
188                 self.super_source_info(source_info);
189             }
190
191             fn visit_ty(&mut self,
192                         ty: $(& $mutability)? Ty<'tcx>,
193                         _: TyContext) {
194                 self.super_ty(ty);
195             }
196
197             fn visit_user_type_projection(
198                 &mut self,
199                 ty: & $($mutability)? UserTypeProjection,
200             ) {
201                 self.super_user_type_projection(ty);
202             }
203
204             fn visit_user_type_annotation(
205                 &mut self,
206                 index: UserTypeAnnotationIndex,
207                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
208             ) {
209                 self.super_user_type_annotation(index, ty);
210             }
211
212             fn visit_region(&mut self,
213                             region: & $($mutability)? ty::Region<'tcx>,
214                             _: Location) {
215                 self.super_region(region);
216             }
217
218             fn visit_const(&mut self,
219                            constant: & $($mutability)? &'tcx ty::Const<'tcx>,
220                            _: Location) {
221                 self.super_const(constant);
222             }
223
224             fn visit_substs(&mut self,
225                             substs: & $($mutability)? SubstsRef<'tcx>,
226                             _: Location) {
227                 self.super_substs(substs);
228             }
229
230             fn visit_local_decl(&mut self,
231                                 local: Local,
232                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
233                 self.super_local_decl(local, local_decl);
234             }
235
236             fn visit_var_debug_info(&mut self,
237                                     var_debug_info: & $($mutability)* VarDebugInfo<'tcx>) {
238                 self.super_var_debug_info(var_debug_info);
239             }
240
241             fn visit_local(&mut self,
242                             _local: & $($mutability)? Local,
243                             _context: PlaceContext,
244                             _location: Location) {
245             }
246
247             fn visit_source_scope(&mut self,
248                                       scope: & $($mutability)? SourceScope) {
249                 self.super_source_scope(scope);
250             }
251
252             // The `super_xxx` methods comprise the default behavior and are
253             // not meant to be overridden.
254
255             fn super_body(
256                 &mut self,
257                 $($mutability)? body: body_cache_type!($($mutability)? '_, 'tcx)
258             ) {
259                 let span = body.span;
260                 if let Some(yield_ty) = &$($mutability)? body.yield_ty {
261                     self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo {
262                         span,
263                         scope: OUTERMOST_SOURCE_SCOPE,
264                     }));
265                 }
266
267                 // for best performance, we want to use an iterator rather
268                 // than a for-loop, to avoid calling `body::Body::invalidate` for
269                 // each basic block.
270                 macro_rules! basic_blocks {
271                     (mut) => (body.basic_blocks_mut().iter_enumerated_mut());
272                     () => (body.basic_blocks().iter_enumerated());
273                 };
274                 for (bb, data) in basic_blocks!($($mutability)?) {
275                     self.visit_basic_block_data(bb, data);
276                 }
277
278                 let body: & $($mutability)? Body<'_> = & $($mutability)? body;
279                 for scope in &$($mutability)? body.source_scopes {
280                     self.visit_source_scope_data(scope);
281                 }
282
283                 self.visit_ty(&$($mutability)? body.return_ty(), TyContext::ReturnTy(SourceInfo {
284                     span: body.span,
285                     scope: OUTERMOST_SOURCE_SCOPE,
286                 }));
287
288                 for local in body.local_decls.indices() {
289                     self.visit_local_decl(local, & $($mutability)? body.local_decls[local]);
290                 }
291
292                 macro_rules! type_annotations {
293                     (mut) => (body.user_type_annotations.iter_enumerated_mut());
294                     () => (body.user_type_annotations.iter_enumerated());
295                 };
296
297                 for (index, annotation) in type_annotations!($($mutability)?) {
298                     self.visit_user_type_annotation(
299                         index, annotation
300                     );
301                 }
302
303                 for var_debug_info in &$($mutability)? body.var_debug_info {
304                     self.visit_var_debug_info(var_debug_info);
305                 }
306
307                 self.visit_span(&$($mutability)? body.span);
308             }
309
310             fn super_basic_block_data(&mut self,
311                                       block: BasicBlock,
312                                       data: & $($mutability)? BasicBlockData<'tcx>) {
313                 let BasicBlockData {
314                     statements,
315                     terminator,
316                     is_cleanup: _
317                 } = data;
318
319                 let mut index = 0;
320                 for statement in statements {
321                     let location = Location { block: block, statement_index: index };
322                     self.visit_statement(statement, location);
323                     index += 1;
324                 }
325
326                 if let Some(terminator) = terminator {
327                     let location = Location { block: block, statement_index: index };
328                     self.visit_terminator(terminator, location);
329                 }
330             }
331
332             fn super_source_scope_data(&mut self, scope_data: & $($mutability)? SourceScopeData) {
333                 let SourceScopeData {
334                     span,
335                     parent_scope,
336                     local_data: _,
337                 } = scope_data;
338
339                 self.visit_span(span);
340                 if let Some(parent_scope) = parent_scope {
341                     self.visit_source_scope(parent_scope);
342                 }
343             }
344
345             fn super_statement(&mut self,
346                                statement: & $($mutability)? Statement<'tcx>,
347                                location: Location) {
348                 let Statement {
349                     source_info,
350                     kind,
351                 } = statement;
352
353                 self.visit_source_info(source_info);
354                 match kind {
355                     StatementKind::Assign(
356                         box(ref $($mutability)? place, ref $($mutability)? rvalue)
357                     ) => {
358                         self.visit_assign(place, rvalue, location);
359                     }
360                     StatementKind::FakeRead(_, place) => {
361                         self.visit_place(
362                             place,
363                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
364                             location
365                         );
366                     }
367                     StatementKind::SetDiscriminant { place, .. } => {
368                         self.visit_place(
369                             place,
370                             PlaceContext::MutatingUse(MutatingUseContext::Store),
371                             location
372                         );
373                     }
374                     StatementKind::StorageLive(local) => {
375                         self.visit_local(
376                             local,
377                             PlaceContext::NonUse(NonUseContext::StorageLive),
378                             location
379                         );
380                     }
381                     StatementKind::StorageDead(local) => {
382                         self.visit_local(
383                             local,
384                             PlaceContext::NonUse(NonUseContext::StorageDead),
385                             location
386                         );
387                     }
388                     StatementKind::InlineAsm(asm) => {
389                         for output in & $($mutability)? asm.outputs[..] {
390                             self.visit_place(
391                                 output,
392                                 PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
393                                 location
394                             );
395                         }
396                         for (span, input) in & $($mutability)? asm.inputs[..] {
397                             self.visit_span(span);
398                             self.visit_operand(input, location);
399                         }
400                     }
401                     StatementKind::Retag(kind, place) => {
402                         self.visit_retag(kind, place, location);
403                     }
404                     StatementKind::AscribeUserType(
405                         box(ref $($mutability)? place, ref $($mutability)? user_ty),
406                         variance
407                     ) => {
408                         self.visit_ascribe_user_ty(place, variance, user_ty, location);
409                     }
410                     StatementKind::Nop => {}
411                 }
412             }
413
414             fn super_assign(&mut self,
415                             place: &$($mutability)? Place<'tcx>,
416                             rvalue: &$($mutability)? Rvalue<'tcx>,
417                             location: Location) {
418                 self.visit_place(
419                     place,
420                     PlaceContext::MutatingUse(MutatingUseContext::Store),
421                     location
422                 );
423                 self.visit_rvalue(rvalue, location);
424             }
425
426             fn super_terminator(&mut self,
427                                 terminator: &$($mutability)? Terminator<'tcx>,
428                                 location: Location) {
429                 let Terminator { source_info, kind } = terminator;
430
431                 self.visit_source_info(source_info);
432                 self.visit_terminator_kind(kind, location);
433             }
434
435             fn super_terminator_kind(&mut self,
436                                      kind: & $($mutability)? TerminatorKind<'tcx>,
437                                      source_location: Location) {
438                 match kind {
439                     TerminatorKind::Goto { .. } |
440                     TerminatorKind::Resume |
441                     TerminatorKind::Abort |
442                     TerminatorKind::Return |
443                     TerminatorKind::GeneratorDrop |
444                     TerminatorKind::Unreachable |
445                     TerminatorKind::FalseEdges { .. } |
446                     TerminatorKind::FalseUnwind { .. } => {
447                     }
448
449                     TerminatorKind::SwitchInt {
450                         discr,
451                         switch_ty,
452                         values: _,
453                         targets: _
454                     } => {
455                         self.visit_operand(discr, source_location);
456                         self.visit_ty(switch_ty, TyContext::Location(source_location));
457                     }
458
459                     TerminatorKind::Drop {
460                         location,
461                         target: _,
462                         unwind: _,
463                     } => {
464                         self.visit_place(
465                             location,
466                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
467                             source_location
468                         );
469                     }
470
471                     TerminatorKind::DropAndReplace {
472                         location,
473                         value,
474                         target: _,
475                         unwind: _,
476                     } => {
477                         self.visit_place(
478                             location,
479                             PlaceContext::MutatingUse(MutatingUseContext::Drop),
480                             source_location
481                         );
482                         self.visit_operand(value, source_location);
483                     }
484
485                     TerminatorKind::Call {
486                         func,
487                         args,
488                         destination,
489                         cleanup: _,
490                         from_hir_call: _,
491                     } => {
492                         self.visit_operand(func, source_location);
493                         for arg in args {
494                             self.visit_operand(arg, source_location);
495                         }
496                         if let Some((destination, _)) = destination {
497                             self.visit_place(
498                                 destination,
499                                 PlaceContext::MutatingUse(MutatingUseContext::Call),
500                                 source_location
501                             );
502                         }
503                     }
504
505                     TerminatorKind::Assert {
506                         cond,
507                         expected: _,
508                         msg,
509                         target: _,
510                         cleanup: _,
511                     } => {
512                         self.visit_operand(cond, source_location);
513                         self.visit_assert_message(msg, source_location);
514                     }
515
516                     TerminatorKind::Yield {
517                         value,
518                         resume: _,
519                         drop: _,
520                     } => {
521                         self.visit_operand(value, source_location);
522                     }
523
524                 }
525             }
526
527             fn super_assert_message(&mut self,
528                                     msg: & $($mutability)? AssertMessage<'tcx>,
529                                     location: Location) {
530                 use crate::mir::interpret::PanicInfo::*;
531                 match msg {
532                     BoundsCheck { len, index } => {
533                         self.visit_operand(len, location);
534                         self.visit_operand(index, location);
535                     }
536                     Panic { .. } | Overflow(_) | OverflowNeg | DivisionByZero | RemainderByZero |
537                     ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
538                         // Nothing to visit
539                     }
540                 }
541             }
542
543             fn super_rvalue(&mut self,
544                             rvalue: & $($mutability)? Rvalue<'tcx>,
545                             location: Location) {
546                 match rvalue {
547                     Rvalue::Use(operand) => {
548                         self.visit_operand(operand, location);
549                     }
550
551                     Rvalue::Repeat(value, _) => {
552                         self.visit_operand(value, location);
553                     }
554
555                     Rvalue::Ref(r, bk, path) => {
556                         self.visit_region(r, location);
557                         let ctx = match bk {
558                             BorrowKind::Shared => PlaceContext::NonMutatingUse(
559                                 NonMutatingUseContext::SharedBorrow
560                             ),
561                             BorrowKind::Shallow => PlaceContext::NonMutatingUse(
562                                 NonMutatingUseContext::ShallowBorrow
563                             ),
564                             BorrowKind::Unique => PlaceContext::NonMutatingUse(
565                                 NonMutatingUseContext::UniqueBorrow
566                             ),
567                             BorrowKind::Mut { .. } =>
568                                 PlaceContext::MutatingUse(MutatingUseContext::Borrow),
569                         };
570                         self.visit_place(path, ctx, location);
571                     }
572
573                     Rvalue::Len(path) => {
574                         self.visit_place(
575                             path,
576                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
577                             location
578                         );
579                     }
580
581                     Rvalue::Cast(_cast_kind, operand, ty) => {
582                         self.visit_operand(operand, location);
583                         self.visit_ty(ty, TyContext::Location(location));
584                     }
585
586                     Rvalue::BinaryOp(_bin_op, lhs, rhs)
587                     | Rvalue::CheckedBinaryOp(_bin_op, lhs, rhs) => {
588                         self.visit_operand(lhs, location);
589                         self.visit_operand(rhs, location);
590                     }
591
592                     Rvalue::UnaryOp(_un_op, op) => {
593                         self.visit_operand(op, location);
594                     }
595
596                     Rvalue::Discriminant(place) => {
597                         self.visit_place(
598                             place,
599                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
600                             location
601                         );
602                     }
603
604                     Rvalue::NullaryOp(_op, ty) => {
605                         self.visit_ty(ty, TyContext::Location(location));
606                     }
607
608                     Rvalue::Aggregate(kind, operands) => {
609                         let kind = &$($mutability)? **kind;
610                         match kind {
611                             AggregateKind::Array(ty) => {
612                                 self.visit_ty(ty, TyContext::Location(location));
613                             }
614                             AggregateKind::Tuple => {
615                             }
616                             AggregateKind::Adt(
617                                 _adt_def,
618                                 _variant_index,
619                                 substs,
620                                 _user_substs,
621                                 _active_field_index
622                             ) => {
623                                 self.visit_substs(substs, location);
624                             }
625                             AggregateKind::Closure(
626                                 _,
627                                 closure_substs
628                             ) => {
629                                 self.visit_substs(closure_substs, location);
630                             }
631                             AggregateKind::Generator(
632                                 _,
633                                 generator_substs,
634                                 _movability,
635                             ) => {
636                                 self.visit_substs(generator_substs, location);
637                             }
638                         }
639
640                         for operand in operands {
641                             self.visit_operand(operand, location);
642                         }
643                     }
644                 }
645             }
646
647             fn super_operand(&mut self,
648                              operand: & $($mutability)? Operand<'tcx>,
649                              location: Location) {
650                 match operand {
651                     Operand::Copy(place) => {
652                         self.visit_place(
653                             place,
654                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
655                             location
656                         );
657                     }
658                     Operand::Move(place) => {
659                         self.visit_place(
660                             place,
661                             PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
662                             location
663                         );
664                     }
665                     Operand::Constant(constant) => {
666                         self.visit_constant(constant, location);
667                     }
668                 }
669             }
670
671             fn super_ascribe_user_ty(&mut self,
672                                      place: & $($mutability)? Place<'tcx>,
673                                      _variance: & $($mutability)? ty::Variance,
674                                      user_ty: & $($mutability)? UserTypeProjection,
675                                      location: Location) {
676                 self.visit_place(
677                     place,
678                     PlaceContext::NonUse(NonUseContext::AscribeUserTy),
679                     location
680                 );
681                 self.visit_user_type_projection(user_ty);
682             }
683
684             fn super_retag(&mut self,
685                            _kind: & $($mutability)? RetagKind,
686                            place: & $($mutability)? Place<'tcx>,
687                            location: Location) {
688                 self.visit_place(
689                     place,
690                     PlaceContext::MutatingUse(MutatingUseContext::Retag),
691                     location,
692                 );
693             }
694
695             fn super_place_base(&mut self,
696                                 place_base: & $($mutability)? PlaceBase<'tcx>,
697                                 context: PlaceContext,
698                                 location: Location) {
699                 match place_base {
700                     PlaceBase::Local(local) => {
701                         self.visit_local(local, context, location);
702                     }
703                     PlaceBase::Static(box Static { kind: _, ty, def_id: _ }) => {
704                         self.visit_ty(& $($mutability)? *ty, TyContext::Location(location));
705                     }
706                 }
707             }
708
709             fn super_local_decl(&mut self,
710                                 local: Local,
711                                 local_decl: & $($mutability)? LocalDecl<'tcx>) {
712                 let LocalDecl {
713                     mutability: _,
714                     ty,
715                     user_ty,
716                     source_info,
717                     internal: _,
718                     local_info: _,
719                     is_block_tail: _,
720                 } = local_decl;
721
722                 self.visit_ty(ty, TyContext::LocalDecl {
723                     local,
724                     source_info: *source_info,
725                 });
726                 for (user_ty, _) in & $($mutability)? user_ty.contents {
727                     self.visit_user_type_projection(user_ty);
728                 }
729                 self.visit_source_info(source_info);
730             }
731
732             fn super_var_debug_info(&mut self,
733                                     var_debug_info: & $($mutability)? VarDebugInfo<'tcx>) {
734                 let VarDebugInfo {
735                     name: _,
736                     source_info,
737                     place,
738                 } = var_debug_info;
739
740                 self.visit_source_info(source_info);
741                 let location = START_BLOCK.start_location();
742                 self.visit_place(
743                     place,
744                     PlaceContext::NonUse(NonUseContext::VarDebugInfo),
745                     location,
746                 );
747             }
748
749             fn super_source_scope(&mut self,
750                                       _scope: & $($mutability)? SourceScope) {
751             }
752
753             fn super_constant(&mut self,
754                               constant: & $($mutability)? Constant<'tcx>,
755                               location: Location) {
756                 let Constant {
757                     span,
758                     user_ty,
759                     literal,
760                 } = constant;
761
762                 self.visit_span(span);
763                 drop(user_ty); // no visit method for this
764                 self.visit_const(literal, location);
765             }
766
767             fn super_span(&mut self, _span: & $($mutability)? Span) {
768             }
769
770             fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
771                 let SourceInfo {
772                     span,
773                     scope,
774                 } = source_info;
775
776                 self.visit_span(span);
777                 self.visit_source_scope(scope);
778             }
779
780             fn super_user_type_projection(
781                 &mut self,
782                 _ty: & $($mutability)? UserTypeProjection,
783             ) {
784             }
785
786             fn super_user_type_annotation(
787                 &mut self,
788                 _index: UserTypeAnnotationIndex,
789                 ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
790             ) {
791                 self.visit_span(& $($mutability)? ty.span);
792                 self.visit_ty(& $($mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
793             }
794
795             fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
796             }
797
798             fn super_region(&mut self, _region: & $($mutability)? ty::Region<'tcx>) {
799             }
800
801             fn super_const(&mut self, _const: & $($mutability)? &'tcx ty::Const<'tcx>) {
802             }
803
804             fn super_substs(&mut self, _substs: & $($mutability)? SubstsRef<'tcx>) {
805             }
806
807             // Convenience methods
808
809             fn visit_location(
810                 &mut self,
811                 body: body_cache_type!($($mutability)? '_, 'tcx),
812                 location: Location
813             ) {
814                 let basic_block = & $($mutability)? body[location.block];
815                 if basic_block.statements.len() == location.statement_index {
816                     if let Some(ref $($mutability)? terminator) = basic_block.terminator {
817                         self.visit_terminator(terminator, location)
818                     }
819                 } else {
820                     let statement = & $($mutability)?
821                         basic_block.statements[location.statement_index];
822                     self.visit_statement(statement, location)
823                 }
824             }
825         }
826     }
827 }
828
829 macro_rules! visit_place_fns {
830     (mut) => (
831         fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
832
833         fn super_place(
834             &mut self,
835             place: &mut Place<'tcx>,
836             context: PlaceContext,
837             location: Location,
838         ) {
839             self.visit_place_base(&mut place.base, context, location);
840
841             if let Some(new_projection) = self.process_projection(&place.projection) {
842                 place.projection = self.tcx().intern_place_elems(&new_projection);
843             }
844         }
845
846         fn process_projection(
847             &mut self,
848             projection: &'a [PlaceElem<'tcx>],
849         ) -> Option<Vec<PlaceElem<'tcx>>> {
850             let mut projection = Cow::Borrowed(projection);
851
852             for i in 0..projection.len() {
853                 if let Some(elem) = projection.get(i) {
854                     if let Some(elem) = self.process_projection_elem(elem) {
855                         // This converts the borrowed projection into `Cow::Owned(_)` and returns a
856                         // clone of the projection so we can mutate and reintern later.
857                         let vec = projection.to_mut();
858                         vec[i] = elem;
859                     }
860                 }
861             }
862
863             match projection {
864                 Cow::Borrowed(_) => None,
865                 Cow::Owned(vec) => Some(vec),
866             }
867         }
868
869         fn process_projection_elem(
870             &mut self,
871             _elem: &PlaceElem<'tcx>,
872         ) -> Option<PlaceElem<'tcx>> {
873             None
874         }
875     );
876
877     () => (
878         fn visit_projection(
879             &mut self,
880             base: &PlaceBase<'tcx>,
881             projection: &[PlaceElem<'tcx>],
882             context: PlaceContext,
883             location: Location,
884         ) {
885             self.super_projection(base, projection, context, location);
886         }
887
888         fn visit_projection_elem(
889             &mut self,
890             base: &PlaceBase<'tcx>,
891             proj_base: &[PlaceElem<'tcx>],
892             elem: &PlaceElem<'tcx>,
893             context: PlaceContext,
894             location: Location,
895         ) {
896             self.super_projection_elem(base, proj_base, elem, context, location);
897         }
898
899         fn super_place(
900             &mut self,
901             place: &Place<'tcx>,
902             context: PlaceContext,
903             location: Location,
904         ) {
905             let mut context = context;
906
907             if !place.projection.is_empty() {
908                 context = if context.is_mutating_use() {
909                     PlaceContext::MutatingUse(MutatingUseContext::Projection)
910                 } else {
911                     PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
912                 };
913             }
914
915             self.visit_place_base(&place.base, context, location);
916
917             self.visit_projection(&place.base,
918                                   &place.projection,
919                                   context,
920                                   location);
921         }
922
923         fn super_projection(
924             &mut self,
925             base: &PlaceBase<'tcx>,
926             projection: &[PlaceElem<'tcx>],
927             context: PlaceContext,
928             location: Location,
929         ) {
930             let mut cursor = projection;
931             while let [proj_base @ .., elem] = cursor {
932                 cursor = proj_base;
933                 self.visit_projection_elem(base, cursor, elem, context, location);
934             }
935         }
936
937         fn super_projection_elem(
938             &mut self,
939             _base: &PlaceBase<'tcx>,
940             _proj_base: &[PlaceElem<'tcx>],
941             elem: &PlaceElem<'tcx>,
942             _context: PlaceContext,
943             location: Location,
944         ) {
945             match elem {
946                 ProjectionElem::Field(_field, ty) => {
947                     self.visit_ty(ty, TyContext::Location(location));
948                 }
949                 ProjectionElem::Index(local) => {
950                     self.visit_local(
951                         local,
952                         PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
953                         location
954                     );
955                 }
956                 ProjectionElem::Deref |
957                 ProjectionElem::Subslice { from: _, to: _, from_end: _ } |
958                 ProjectionElem::ConstantIndex { offset: _,
959                                                 min_length: _,
960                                                 from_end: _ } |
961                 ProjectionElem::Downcast(_, _) => {
962                 }
963             }
964         }
965     );
966 }
967
968 make_mir_visitor!(Visitor,);
969 make_mir_visitor!(MutVisitor,mut);
970
971 pub trait MirVisitable<'tcx> {
972     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>);
973 }
974
975 impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> {
976     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)
977     {
978         visitor.visit_statement(self, location)
979     }
980 }
981
982 impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> {
983     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)
984     {
985         visitor.visit_terminator(self, location)
986     }
987 }
988
989 impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
990     fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>)
991     {
992         visitor.visit_terminator(self.as_ref().unwrap(), location)
993     }
994 }
995
996 /// Extra information passed to `visit_ty` and friends to give context
997 /// about where the type etc appears.
998 #[derive(Debug)]
999 pub enum TyContext {
1000     LocalDecl {
1001         /// The index of the local variable we are visiting.
1002         local: Local,
1003
1004         /// The source location where this local variable was declared.
1005         source_info: SourceInfo,
1006     },
1007
1008     /// The inferred type of a user type annotation.
1009     UserTy(Span),
1010
1011     /// The return type of the function.
1012     ReturnTy(SourceInfo),
1013
1014     YieldTy(SourceInfo),
1015
1016     /// A type found at some location.
1017     Location(Location),
1018 }
1019
1020 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1021 pub enum NonMutatingUseContext {
1022     /// Being inspected in some way, like loading a len.
1023     Inspect,
1024     /// Consumed as part of an operand.
1025     Copy,
1026     /// Consumed as part of an operand.
1027     Move,
1028     /// Shared borrow.
1029     SharedBorrow,
1030     /// Shallow borrow.
1031     ShallowBorrow,
1032     /// Unique borrow.
1033     UniqueBorrow,
1034     /// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
1035     /// For example, the projection `x.y` is not marked as a mutation in these cases:
1036     ///
1037     ///     z = x.y;
1038     ///     f(&x.y);
1039     ///
1040     Projection,
1041 }
1042
1043 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1044 pub enum MutatingUseContext {
1045     /// Appears as LHS of an assignment.
1046     Store,
1047     /// Can often be treated as a `Store`, but needs to be separate because
1048     /// ASM is allowed to read outputs as well, so a `Store`-`AsmOutput` sequence
1049     /// cannot be simplified the way a `Store`-`Store` can be.
1050     AsmOutput,
1051     /// Destination of a call.
1052     Call,
1053     /// Being dropped.
1054     Drop,
1055     /// Mutable borrow.
1056     Borrow,
1057     /// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
1058     /// For example, the projection `x.y` is marked as a mutation in these cases:
1059     ///
1060     ///     x.y = ...;
1061     ///     f(&mut x.y);
1062     ///
1063     Projection,
1064     /// Retagging, a "Stacked Borrows" shadow state operation
1065     Retag,
1066 }
1067
1068 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1069 pub enum NonUseContext {
1070     /// Starting a storage live range.
1071     StorageLive,
1072     /// Ending a storage live range.
1073     StorageDead,
1074     /// User type annotation assertions for NLL.
1075     AscribeUserTy,
1076     /// The data of an user variable, for debug info.
1077     VarDebugInfo,
1078 }
1079
1080 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1081 pub enum PlaceContext {
1082     NonMutatingUse(NonMutatingUseContext),
1083     MutatingUse(MutatingUseContext),
1084     NonUse(NonUseContext),
1085 }
1086
1087 impl PlaceContext {
1088     /// Returns `true` if this place context represents a drop.
1089     pub fn is_drop(&self) -> bool {
1090         match *self {
1091             PlaceContext::MutatingUse(MutatingUseContext::Drop) => true,
1092             _ => false,
1093         }
1094     }
1095
1096     /// Returns `true` if this place context represents a borrow.
1097     pub fn is_borrow(&self) -> bool {
1098         match *self {
1099             PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
1100             PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
1101             PlaceContext::NonMutatingUse(NonMutatingUseContext::UniqueBorrow) |
1102             PlaceContext::MutatingUse(MutatingUseContext::Borrow) => true,
1103             _ => false,
1104         }
1105     }
1106
1107     /// Returns `true` if this place context represents a storage live or storage dead marker.
1108     pub fn is_storage_marker(&self) -> bool {
1109         match *self {
1110             PlaceContext::NonUse(NonUseContext::StorageLive) |
1111             PlaceContext::NonUse(NonUseContext::StorageDead) => true,
1112             _ => false,
1113         }
1114     }
1115
1116     /// Returns `true` if this place context represents a storage live marker.
1117     pub fn is_storage_live_marker(&self) -> bool {
1118         match *self {
1119             PlaceContext::NonUse(NonUseContext::StorageLive) => true,
1120             _ => false,
1121         }
1122     }
1123
1124     /// Returns `true` if this place context represents a storage dead marker.
1125     pub fn is_storage_dead_marker(&self) -> bool {
1126         match *self {
1127             PlaceContext::NonUse(NonUseContext::StorageDead) => true,
1128             _ => false,
1129         }
1130     }
1131
1132     /// Returns `true` if this place context represents a use that potentially changes the value.
1133     pub fn is_mutating_use(&self) -> bool {
1134         match *self {
1135             PlaceContext::MutatingUse(..) => true,
1136             _ => false,
1137         }
1138     }
1139
1140     /// Returns `true` if this place context represents a use that does not change the value.
1141     pub fn is_nonmutating_use(&self) -> bool {
1142         match *self {
1143             PlaceContext::NonMutatingUse(..) => true,
1144             _ => false,
1145         }
1146     }
1147
1148     /// Returns `true` if this place context represents a use.
1149     pub fn is_use(&self) -> bool {
1150         match *self {
1151             PlaceContext::NonUse(..) => false,
1152             _ => true,
1153         }
1154     }
1155
1156     /// Returns `true` if this place context represents an assignment statement.
1157     pub fn is_place_assignment(&self) -> bool {
1158         match *self {
1159             PlaceContext::MutatingUse(MutatingUseContext::Store) |
1160             PlaceContext::MutatingUse(MutatingUseContext::Call) |
1161             PlaceContext::MutatingUse(MutatingUseContext::AsmOutput) => true,
1162             _ => false,
1163         }
1164     }
1165 }