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