]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/expr_use_visitor.rs
Remove HIR based const qualification
[rust.git] / src / librustc / middle / expr_use_visitor.rs
1 //! A different sort of visitor for walking fn bodies. Unlike the
2 //! normal visitor, which just walks the entire body in one shot, the
3 //! `ExprUseVisitor` determines how expressions are being used.
4
5 pub use self::LoanCause::*;
6 pub use self::ConsumeMode::*;
7 pub use self::MoveReason::*;
8 pub use self::MatchMode::*;
9 use self::TrackMatchMode::*;
10 use self::OverloadedCallType::*;
11
12 use crate::hir::def::{CtorOf, Res, DefKind};
13 use crate::hir::def_id::DefId;
14 use crate::hir::ptr::P;
15 use crate::infer::InferCtxt;
16 use crate::middle::mem_categorization as mc;
17 use crate::middle::region;
18 use crate::ty::{self, DefIdTree, TyCtxt, adjustment};
19
20 use crate::hir::{self, PatKind};
21 use std::rc::Rc;
22 use syntax_pos::Span;
23
24 ///////////////////////////////////////////////////////////////////////////
25 // The Delegate trait
26
27 /// This trait defines the callbacks you can expect to receive when
28 /// employing the ExprUseVisitor.
29 pub trait Delegate<'tcx> {
30     // The value found at `cmt` is either copied or moved, depending
31     // on mode.
32     fn consume(&mut self,
33                consume_id: hir::HirId,
34                consume_span: Span,
35                cmt: &mc::cmt_<'tcx>,
36                mode: ConsumeMode);
37
38     // The value found at `cmt` has been determined to match the
39     // pattern binding `matched_pat`, and its subparts are being
40     // copied or moved depending on `mode`.  Note that `matched_pat`
41     // is called on all variant/structs in the pattern (i.e., the
42     // interior nodes of the pattern's tree structure) while
43     // consume_pat is called on the binding identifiers in the pattern
44     // (which are leaves of the pattern's tree structure).
45     //
46     // Note that variants/structs and identifiers are disjoint; thus
47     // `matched_pat` and `consume_pat` are never both called on the
48     // same input pattern structure (though of `consume_pat` can be
49     // called on a subpart of an input passed to `matched_pat).
50     fn matched_pat(&mut self,
51                    matched_pat: &hir::Pat,
52                    cmt: &mc::cmt_<'tcx>,
53                    mode: MatchMode);
54
55     // The value found at `cmt` is either copied or moved via the
56     // pattern binding `consume_pat`, depending on mode.
57     fn consume_pat(&mut self,
58                    consume_pat: &hir::Pat,
59                    cmt: &mc::cmt_<'tcx>,
60                    mode: ConsumeMode);
61
62     // The value found at `borrow` is being borrowed at the point
63     // `borrow_id` for the region `loan_region` with kind `bk`.
64     fn borrow(&mut self,
65               borrow_id: hir::HirId,
66               borrow_span: Span,
67               cmt: &mc::cmt_<'tcx>,
68               loan_region: ty::Region<'tcx>,
69               bk: ty::BorrowKind,
70               loan_cause: LoanCause);
71
72     // The local variable `id` is declared but not initialized.
73     fn decl_without_init(&mut self,
74                          id: hir::HirId,
75                          span: Span);
76
77     // The path at `cmt` is being assigned to.
78     fn mutate(&mut self,
79               assignment_id: hir::HirId,
80               assignment_span: Span,
81               assignee_cmt: &mc::cmt_<'tcx>,
82               mode: MutateMode);
83
84     // A nested closure or generator - only one layer deep.
85     fn nested_body(&mut self, _body_id: hir::BodyId) {}
86 }
87
88 #[derive(Copy, Clone, PartialEq, Debug)]
89 pub enum LoanCause {
90     ClosureCapture(Span),
91     AddrOf,
92     AutoRef,
93     AutoUnsafe,
94     RefBinding,
95     OverloadedOperator,
96     ClosureInvocation,
97     ForLoop,
98     MatchDiscriminant
99 }
100
101 #[derive(Copy, Clone, PartialEq, Debug)]
102 pub enum ConsumeMode {
103     Copy,                // reference to x where x has a type that copies
104     Move(MoveReason),    // reference to x where x has a type that moves
105 }
106
107 #[derive(Copy, Clone, PartialEq, Debug)]
108 pub enum MoveReason {
109     DirectRefMove,
110     PatBindingMove,
111     CaptureMove,
112 }
113
114 #[derive(Copy, Clone, PartialEq, Debug)]
115 pub enum MatchMode {
116     NonBindingMatch,
117     BorrowingMatch,
118     CopyingMatch,
119     MovingMatch,
120 }
121
122 #[derive(Copy, Clone, PartialEq, Debug)]
123 enum TrackMatchMode {
124     Unknown,
125     Definite(MatchMode),
126     Conflicting,
127 }
128
129 impl TrackMatchMode {
130     // Builds up the whole match mode for a pattern from its constituent
131     // parts.  The lattice looks like this:
132     //
133     //          Conflicting
134     //            /     \
135     //           /       \
136     //      Borrowing   Moving
137     //           \       /
138     //            \     /
139     //            Copying
140     //               |
141     //          NonBinding
142     //               |
143     //            Unknown
144     //
145     // examples:
146     //
147     // * `(_, some_int)` pattern is Copying, since
148     //   NonBinding + Copying => Copying
149     //
150     // * `(some_int, some_box)` pattern is Moving, since
151     //   Copying + Moving => Moving
152     //
153     // * `(ref x, some_box)` pattern is Conflicting, since
154     //   Borrowing + Moving => Conflicting
155     //
156     // Note that the `Unknown` and `Conflicting` states are
157     // represented separately from the other more interesting
158     // `Definite` states, which simplifies logic here somewhat.
159     fn lub(&mut self, mode: MatchMode) {
160         *self = match (*self, mode) {
161             // Note that clause order below is very significant.
162             (Unknown, new) => Definite(new),
163             (Definite(old), new) if old == new => Definite(old),
164
165             (Definite(old), NonBindingMatch) => Definite(old),
166             (Definite(NonBindingMatch), new) => Definite(new),
167
168             (Definite(old), CopyingMatch) => Definite(old),
169             (Definite(CopyingMatch), new) => Definite(new),
170
171             (Definite(_), _) => Conflicting,
172             (Conflicting, _) => *self,
173         };
174     }
175
176     fn match_mode(&self) -> MatchMode {
177         match *self {
178             Unknown => NonBindingMatch,
179             Definite(mode) => mode,
180             Conflicting => {
181                 // Conservatively return MovingMatch to let the
182                 // compiler continue to make progress.
183                 MovingMatch
184             }
185         }
186     }
187 }
188
189 #[derive(Copy, Clone, PartialEq, Debug)]
190 pub enum MutateMode {
191     Init,
192     JustWrite,    // x = y
193     WriteAndRead, // x += y
194 }
195
196 #[derive(Copy, Clone)]
197 enum OverloadedCallType {
198     FnOverloadedCall,
199     FnMutOverloadedCall,
200     FnOnceOverloadedCall,
201 }
202
203 impl OverloadedCallType {
204     fn from_trait_id(tcx: TyCtxt<'_>, trait_id: DefId) -> OverloadedCallType {
205         for &(maybe_function_trait, overloaded_call_type) in &[
206             (tcx.lang_items().fn_once_trait(), FnOnceOverloadedCall),
207             (tcx.lang_items().fn_mut_trait(), FnMutOverloadedCall),
208             (tcx.lang_items().fn_trait(), FnOverloadedCall)
209         ] {
210             match maybe_function_trait {
211                 Some(function_trait) if function_trait == trait_id => {
212                     return overloaded_call_type
213                 }
214                 _ => continue,
215             }
216         }
217
218         bug!("overloaded call didn't map to known function trait")
219     }
220
221     fn from_method_id(tcx: TyCtxt<'_>, method_id: DefId) -> OverloadedCallType {
222         let method = tcx.associated_item(method_id);
223         OverloadedCallType::from_trait_id(tcx, method.container.id())
224     }
225 }
226
227 ///////////////////////////////////////////////////////////////////////////
228 // The ExprUseVisitor type
229 //
230 // This is the code that actually walks the tree.
231 pub struct ExprUseVisitor<'a, 'tcx> {
232     mc: mc::MemCategorizationContext<'a, 'tcx>,
233     delegate: &'a mut dyn Delegate<'tcx>,
234     param_env: ty::ParamEnv<'tcx>,
235 }
236
237 // If the MC results in an error, it's because the type check
238 // failed (or will fail, when the error is uncovered and reported
239 // during writeback). In this case, we just ignore this part of the
240 // code.
241 //
242 // Note that this macro appears similar to try!(), but, unlike try!(),
243 // it does not propagate the error.
244 macro_rules! return_if_err {
245     ($inp: expr) => (
246         match $inp {
247             Ok(v) => v,
248             Err(()) => {
249                 debug!("mc reported err");
250                 return
251             }
252         }
253     )
254 }
255
256 impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
257     /// Creates the ExprUseVisitor, configuring it with the various options provided:
258     ///
259     /// - `delegate` -- who receives the callbacks
260     /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
261     /// - `region_scope_tree` --- region scope tree for the code being analyzed
262     /// - `tables` --- typeck results for the code being analyzed
263     ///
264     /// See also `with_infer`, which is used *during* typeck.
265     pub fn new(
266         delegate: &'a mut (dyn Delegate<'tcx> + 'a),
267         tcx: TyCtxt<'tcx>,
268         body_owner: DefId,
269         param_env: ty::ParamEnv<'tcx>,
270         region_scope_tree: &'a region::ScopeTree,
271         tables: &'a ty::TypeckTables<'tcx>,
272     ) -> Self {
273         ExprUseVisitor {
274             mc: mc::MemCategorizationContext::new(tcx,
275                                                   param_env,
276                                                   body_owner,
277                                                   region_scope_tree,
278                                                   tables),
279             delegate,
280             param_env,
281         }
282     }
283 }
284
285 impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
286     pub fn with_infer(
287         delegate: &'a mut (dyn Delegate<'tcx> + 'a),
288         infcx: &'a InferCtxt<'a, 'tcx>,
289         body_owner: DefId,
290         param_env: ty::ParamEnv<'tcx>,
291         region_scope_tree: &'a region::ScopeTree,
292         tables: &'a ty::TypeckTables<'tcx>,
293     ) -> Self {
294         ExprUseVisitor {
295             mc: mc::MemCategorizationContext::with_infer(
296                 infcx,
297                 param_env,
298                 body_owner,
299                 region_scope_tree,
300                 tables,
301             ),
302             delegate,
303             param_env,
304         }
305     }
306
307     pub fn consume_body(&mut self, body: &hir::Body) {
308         debug!("consume_body(body={:?})", body);
309
310         for param in &body.params {
311             let param_ty = return_if_err!(self.mc.pat_ty_adjusted(&param.pat));
312             debug!("consume_body: param_ty = {:?}", param_ty);
313
314             let param_cmt = Rc::new(self.mc.cat_rvalue(
315                 param.hir_id,
316                 param.pat.span,
317                 param_ty));
318
319             self.walk_irrefutable_pat(param_cmt, &param.pat);
320         }
321
322         self.consume_expr(&body.value);
323     }
324
325     fn tcx(&self) -> TyCtxt<'tcx> {
326         self.mc.tcx
327     }
328
329     fn delegate_consume(&mut self,
330                         consume_id: hir::HirId,
331                         consume_span: Span,
332                         cmt: &mc::cmt_<'tcx>) {
333         debug!("delegate_consume(consume_id={}, cmt={:?})",
334                consume_id, cmt);
335
336         let mode = copy_or_move(&self.mc, self.param_env, cmt, DirectRefMove);
337         self.delegate.consume(consume_id, consume_span, cmt, mode);
338     }
339
340     fn consume_exprs(&mut self, exprs: &[hir::Expr]) {
341         for expr in exprs {
342             self.consume_expr(&expr);
343         }
344     }
345
346     pub fn consume_expr(&mut self, expr: &hir::Expr) {
347         debug!("consume_expr(expr={:?})", expr);
348
349         let cmt = return_if_err!(self.mc.cat_expr(expr));
350         self.delegate_consume(expr.hir_id, expr.span, &cmt);
351         self.walk_expr(expr);
352     }
353
354     fn mutate_expr(&mut self,
355                    span: Span,
356                    assignment_expr: &hir::Expr,
357                    expr: &hir::Expr,
358                    mode: MutateMode) {
359         let cmt = return_if_err!(self.mc.cat_expr(expr));
360         self.delegate.mutate(assignment_expr.hir_id, span, &cmt, mode);
361         self.walk_expr(expr);
362     }
363
364     fn borrow_expr(&mut self,
365                    expr: &hir::Expr,
366                    r: ty::Region<'tcx>,
367                    bk: ty::BorrowKind,
368                    cause: LoanCause) {
369         debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})",
370                expr, r, bk);
371
372         let cmt = return_if_err!(self.mc.cat_expr(expr));
373         self.delegate.borrow(expr.hir_id, expr.span, &cmt, r, bk, cause);
374
375         self.walk_expr(expr)
376     }
377
378     fn select_from_expr(&mut self, expr: &hir::Expr) {
379         self.walk_expr(expr)
380     }
381
382     pub fn walk_expr(&mut self, expr: &hir::Expr) {
383         debug!("walk_expr(expr={:?})", expr);
384
385         self.walk_adjustment(expr);
386
387         match expr.kind {
388             hir::ExprKind::Path(_) => { }
389
390             hir::ExprKind::Type(ref subexpr, _) => {
391                 self.walk_expr(&subexpr)
392             }
393
394             hir::ExprKind::Unary(hir::UnDeref, ref base) => { // *base
395                 self.select_from_expr(&base);
396             }
397
398             hir::ExprKind::Field(ref base, _) => { // base.f
399                 self.select_from_expr(&base);
400             }
401
402             hir::ExprKind::Index(ref lhs, ref rhs) => { // lhs[rhs]
403                 self.select_from_expr(&lhs);
404                 self.consume_expr(&rhs);
405             }
406
407             hir::ExprKind::Call(ref callee, ref args) => { // callee(args)
408                 self.walk_callee(expr, &callee);
409                 self.consume_exprs(args);
410             }
411
412             hir::ExprKind::MethodCall(.., ref args) => { // callee.m(args)
413                 self.consume_exprs(args);
414             }
415
416             hir::ExprKind::Struct(_, ref fields, ref opt_with) => {
417                 self.walk_struct_expr(fields, opt_with);
418             }
419
420             hir::ExprKind::Tup(ref exprs) => {
421                 self.consume_exprs(exprs);
422             }
423
424             hir::ExprKind::Match(ref discr, ref arms, _) => {
425                 let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr)));
426                 let r = self.tcx().lifetimes.re_empty;
427                 self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant);
428
429                 // treatment of the discriminant is handled while walking the arms.
430                 for arm in arms {
431                     let mode = self.arm_move_mode(discr_cmt.clone(), arm);
432                     let mode = mode.match_mode();
433                     self.walk_arm(discr_cmt.clone(), arm, mode);
434                 }
435             }
436
437             hir::ExprKind::Array(ref exprs) => {
438                 self.consume_exprs(exprs);
439             }
440
441             hir::ExprKind::AddrOf(m, ref base) => {   // &base
442                 // make sure that the thing we are pointing out stays valid
443                 // for the lifetime `scope_r` of the resulting ptr:
444                 let expr_ty = return_if_err!(self.mc.expr_ty(expr));
445                 if let ty::Ref(r, _, _) = expr_ty.kind {
446                     let bk = ty::BorrowKind::from_mutbl(m);
447                     self.borrow_expr(&base, r, bk, AddrOf);
448                 }
449             }
450
451             hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => {
452                 for (o, output) in ia.outputs.iter().zip(outputs) {
453                     if o.is_indirect {
454                         self.consume_expr(output);
455                     } else {
456                         self.mutate_expr(
457                             output.span,
458                             expr,
459                             output,
460                             if o.is_rw {
461                                 MutateMode::WriteAndRead
462                             } else {
463                                 MutateMode::JustWrite
464                             },
465                         );
466                     }
467                 }
468                 self.consume_exprs(inputs);
469             }
470
471             hir::ExprKind::Continue(..) |
472             hir::ExprKind::Lit(..) |
473             hir::ExprKind::Err => {}
474
475             hir::ExprKind::Loop(ref blk, _, _) => {
476                 self.walk_block(&blk);
477             }
478
479             hir::ExprKind::Unary(_, ref lhs) => {
480                 self.consume_expr(&lhs);
481             }
482
483             hir::ExprKind::Binary(_, ref lhs, ref rhs) => {
484                 self.consume_expr(&lhs);
485                 self.consume_expr(&rhs);
486             }
487
488             hir::ExprKind::Block(ref blk, _) => {
489                 self.walk_block(&blk);
490             }
491
492             hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => {
493                 if let Some(ref expr) = *opt_expr {
494                     self.consume_expr(&expr);
495                 }
496             }
497
498             hir::ExprKind::Assign(ref lhs, ref rhs) => {
499                 self.mutate_expr(expr.span, expr, &lhs, MutateMode::JustWrite);
500                 self.consume_expr(&rhs);
501             }
502
503             hir::ExprKind::Cast(ref base, _) => {
504                 self.consume_expr(&base);
505             }
506
507             hir::ExprKind::DropTemps(ref expr) => {
508                 self.consume_expr(&expr);
509             }
510
511             hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => {
512                 if self.mc.tables.is_method_call(expr) {
513                     self.consume_expr(lhs);
514                 } else {
515                     self.mutate_expr(expr.span, expr, &lhs, MutateMode::WriteAndRead);
516                 }
517                 self.consume_expr(&rhs);
518             }
519
520             hir::ExprKind::Repeat(ref base, _) => {
521                 self.consume_expr(&base);
522             }
523
524             hir::ExprKind::Closure(_, _, body_id, fn_decl_span, _) => {
525                 self.delegate.nested_body(body_id);
526                 self.walk_captures(expr, fn_decl_span);
527             }
528
529             hir::ExprKind::Box(ref base) => {
530                 self.consume_expr(&base);
531             }
532
533             hir::ExprKind::Yield(ref value, _) => {
534                 self.consume_expr(&value);
535             }
536         }
537     }
538
539     fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) {
540         let callee_ty = return_if_err!(self.mc.expr_ty_adjusted(callee));
541         debug!("walk_callee: callee={:?} callee_ty={:?}",
542                callee, callee_ty);
543         match callee_ty.kind {
544             ty::FnDef(..) | ty::FnPtr(_) => {
545                 self.consume_expr(callee);
546             }
547             ty::Error => { }
548             _ => {
549                 if let Some(def_id) = self.mc.tables.type_dependent_def_id(call.hir_id) {
550                     let call_scope = region::Scope {
551                         id: call.hir_id.local_id,
552                         data: region::ScopeData::Node
553                     };
554                     match OverloadedCallType::from_method_id(self.tcx(), def_id) {
555                         FnMutOverloadedCall => {
556                             let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope));
557                             self.borrow_expr(callee,
558                                             call_scope_r,
559                                             ty::MutBorrow,
560                                             ClosureInvocation);
561                         }
562                         FnOverloadedCall => {
563                             let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope));
564                             self.borrow_expr(callee,
565                                             call_scope_r,
566                                             ty::ImmBorrow,
567                                             ClosureInvocation);
568                         }
569                         FnOnceOverloadedCall => self.consume_expr(callee),
570                     }
571                 } else {
572                     self.tcx().sess.delay_span_bug(call.span,
573                                                    "no type-dependent def for overloaded call");
574                 }
575             }
576         }
577     }
578
579     fn walk_stmt(&mut self, stmt: &hir::Stmt) {
580         match stmt.kind {
581             hir::StmtKind::Local(ref local) => {
582                 self.walk_local(&local);
583             }
584
585             hir::StmtKind::Item(_) => {
586                 // We don't visit nested items in this visitor,
587                 // only the fn body we were given.
588             }
589
590             hir::StmtKind::Expr(ref expr) |
591             hir::StmtKind::Semi(ref expr) => {
592                 self.consume_expr(&expr);
593             }
594         }
595     }
596
597     fn walk_local(&mut self, local: &hir::Local) {
598         match local.init {
599             None => {
600                 local.pat.each_binding(|_, hir_id, span, _| {
601                     self.delegate.decl_without_init(hir_id, span);
602                 })
603             }
604
605             Some(ref expr) => {
606                 // Variable declarations with
607                 // initializers are considered
608                 // "assigns", which is handled by
609                 // `walk_pat`:
610                 self.walk_expr(&expr);
611                 let init_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&expr)));
612                 self.walk_irrefutable_pat(init_cmt, &local.pat);
613             }
614         }
615     }
616
617     /// Indicates that the value of `blk` will be consumed, meaning either copied or moved
618     /// depending on its type.
619     fn walk_block(&mut self, blk: &hir::Block) {
620         debug!("walk_block(blk.hir_id={})", blk.hir_id);
621
622         for stmt in &blk.stmts {
623             self.walk_stmt(stmt);
624         }
625
626         if let Some(ref tail_expr) = blk.expr {
627             self.consume_expr(&tail_expr);
628         }
629     }
630
631     fn walk_struct_expr(&mut self,
632                         fields: &[hir::Field],
633                         opt_with: &Option<P<hir::Expr>>) {
634         // Consume the expressions supplying values for each field.
635         for field in fields {
636             self.consume_expr(&field.expr);
637         }
638
639         let with_expr = match *opt_with {
640             Some(ref w) => &**w,
641             None => { return; }
642         };
643
644         let with_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&with_expr)));
645
646         // Select just those fields of the `with`
647         // expression that will actually be used
648         match with_cmt.ty.kind {
649             ty::Adt(adt, substs) if adt.is_struct() => {
650                 // Consume those fields of the with expression that are needed.
651                 for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() {
652                     let is_mentioned = fields.iter().any(|f| {
653                         self.tcx().field_index(f.hir_id, self.mc.tables) == f_index
654                     });
655                     if !is_mentioned {
656                         let cmt_field = self.mc.cat_field(
657                             &*with_expr,
658                             with_cmt.clone(),
659                             f_index,
660                             with_field.ident,
661                             with_field.ty(self.tcx(), substs)
662                         );
663                         self.delegate_consume(with_expr.hir_id, with_expr.span, &cmt_field);
664                     }
665                 }
666             }
667             _ => {
668                 // the base expression should always evaluate to a
669                 // struct; however, when EUV is run during typeck, it
670                 // may not. This will generate an error earlier in typeck,
671                 // so we can just ignore it.
672                 if !self.tcx().sess.has_errors() {
673                     span_bug!(
674                         with_expr.span,
675                         "with expression doesn't evaluate to a struct");
676                 }
677             }
678         }
679
680         // walk the with expression so that complex expressions
681         // are properly handled.
682         self.walk_expr(with_expr);
683     }
684
685     // Invoke the appropriate delegate calls for anything that gets
686     // consumed or borrowed as part of the automatic adjustment
687     // process.
688     fn walk_adjustment(&mut self, expr: &hir::Expr) {
689         let adjustments = self.mc.tables.expr_adjustments(expr);
690         let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr));
691         for adjustment in adjustments {
692             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
693             match adjustment.kind {
694                 adjustment::Adjust::NeverToAny |
695                 adjustment::Adjust::Pointer(_)  => {
696                     // Creating a closure/fn-pointer or unsizing consumes
697                     // the input and stores it into the resulting rvalue.
698                     self.delegate_consume(expr.hir_id, expr.span, &cmt);
699                 }
700
701                 adjustment::Adjust::Deref(None) => {}
702
703                 // Autoderefs for overloaded Deref calls in fact reference
704                 // their receiver. That is, if we have `(*x)` where `x`
705                 // is of type `Rc<T>`, then this in fact is equivalent to
706                 // `x.deref()`. Since `deref()` is declared with `&self`,
707                 // this is an autoref of `x`.
708                 adjustment::Adjust::Deref(Some(ref deref)) => {
709                     let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
710                     self.delegate.borrow(expr.hir_id, expr.span, &cmt, deref.region, bk, AutoRef);
711                 }
712
713                 adjustment::Adjust::Borrow(ref autoref) => {
714                     self.walk_autoref(expr, &cmt, autoref);
715                 }
716             }
717             cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment));
718         }
719     }
720
721     /// Walks the autoref `autoref` applied to the autoderef'd
722     /// `expr`. `cmt_base` is the mem-categorized form of `expr`
723     /// after all relevant autoderefs have occurred.
724     fn walk_autoref(&mut self,
725                     expr: &hir::Expr,
726                     cmt_base: &mc::cmt_<'tcx>,
727                     autoref: &adjustment::AutoBorrow<'tcx>) {
728         debug!("walk_autoref(expr.hir_id={} cmt_base={:?} autoref={:?})",
729                expr.hir_id,
730                cmt_base,
731                autoref);
732
733         match *autoref {
734             adjustment::AutoBorrow::Ref(r, m) => {
735                 self.delegate.borrow(expr.hir_id,
736                                      expr.span,
737                                      cmt_base,
738                                      r,
739                                      ty::BorrowKind::from_mutbl(m.into()),
740                                      AutoRef);
741             }
742
743             adjustment::AutoBorrow::RawPtr(m) => {
744                 debug!("walk_autoref: expr.hir_id={} cmt_base={:?}",
745                        expr.hir_id,
746                        cmt_base);
747
748                 // Converting from a &T to *T (or &mut T to *mut T) is
749                 // treated as borrowing it for the enclosing temporary
750                 // scope.
751                 let r = self.tcx().mk_region(ty::ReScope(
752                     region::Scope {
753                         id: expr.hir_id.local_id,
754                         data: region::ScopeData::Node
755                     }));
756
757                 self.delegate.borrow(expr.hir_id,
758                                      expr.span,
759                                      cmt_base,
760                                      r,
761                                      ty::BorrowKind::from_mutbl(m),
762                                      AutoUnsafe);
763             }
764         }
765     }
766
767     fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode {
768         let mut mode = Unknown;
769         self.determine_pat_move_mode(discr_cmt.clone(), &arm.pat, &mut mode);
770         mode
771     }
772
773     fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, mode: MatchMode) {
774         self.walk_pat(discr_cmt.clone(), &arm.pat, mode);
775
776         if let Some(hir::Guard::If(ref e)) = arm.guard {
777             self.consume_expr(e)
778         }
779
780         self.consume_expr(&arm.body);
781     }
782
783     /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
784     /// let binding, and *not* a match arm or nested pat.)
785     fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) {
786         let mut mode = Unknown;
787         self.determine_pat_move_mode(cmt_discr.clone(), pat, &mut mode);
788         let mode = mode.match_mode();
789         self.walk_pat(cmt_discr, pat, mode);
790     }
791
792     /// Identifies any bindings within `pat` and accumulates within
793     /// `mode` whether the overall pattern/match structure is a move,
794     /// copy, or borrow.
795     fn determine_pat_move_mode(&mut self,
796                                cmt_discr: mc::cmt<'tcx>,
797                                pat: &hir::Pat,
798                                mode: &mut TrackMatchMode) {
799         debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr, pat);
800
801         return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
802             if let PatKind::Binding(..) = pat.kind {
803                 let bm = *self.mc.tables.pat_binding_modes()
804                                         .get(pat.hir_id)
805                                         .expect("missing binding mode");
806                 match bm {
807                     ty::BindByReference(..) =>
808                         mode.lub(BorrowingMatch),
809                     ty::BindByValue(..) => {
810                         match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) {
811                             Copy => mode.lub(CopyingMatch),
812                             Move(..) => mode.lub(MovingMatch),
813                         }
814                     }
815                 }
816             }
817         }));
818     }
819
820     /// The core driver for walking a pattern; `match_mode` must be
821     /// established up front, e.g., via `determine_pat_move_mode` (see
822     /// also `walk_irrefutable_pat` for patterns that stand alone).
823     fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) {
824         debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat);
825
826         let tcx = self.tcx();
827         let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self;
828         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| {
829             if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
830                 debug!(
831                     "walk_pat: binding cmt_pat={:?} pat={:?} match_mode={:?}",
832                     cmt_pat,
833                     pat,
834                     match_mode,
835                 );
836                 if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) {
837                     debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
838
839                     // pat_ty: the type of the binding being produced.
840                     let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
841                     debug!("walk_pat: pat_ty={:?}", pat_ty);
842
843                     // Each match binding is effectively an assignment to the
844                     // binding being produced.
845                     let def = Res::Local(canonical_id);
846                     if let Ok(ref binding_cmt) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) {
847                         delegate.mutate(pat.hir_id, pat.span, binding_cmt, MutateMode::Init);
848                     }
849
850                     // It is also a borrow or copy/move of the value being matched.
851                     match bm {
852                         ty::BindByReference(m) => {
853                             if let ty::Ref(r, _, _) = pat_ty.kind {
854                                 let bk = ty::BorrowKind::from_mutbl(m);
855                                 delegate.borrow(pat.hir_id, pat.span, &cmt_pat, r, bk, RefBinding);
856                             }
857                         }
858                         ty::BindByValue(..) => {
859                             let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove);
860                             debug!("walk_pat binding consuming pat");
861                             delegate.consume_pat(pat, &cmt_pat, mode);
862                         }
863                     }
864                 } else {
865                     tcx.sess.delay_span_bug(pat.span, "missing binding mode");
866                 }
867             }
868         }));
869
870         // Do a second pass over the pattern, calling `matched_pat` on
871         // the interior nodes (enum variants and structs), as opposed
872         // to the above loop's visit of than the bindings that form
873         // the leaves of the pattern tree structure.
874         return_if_err!(mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| {
875             let qpath = match pat.kind {
876                 PatKind::Path(ref qpath) |
877                 PatKind::TupleStruct(ref qpath, ..) |
878                 PatKind::Struct(ref qpath, ..) => qpath,
879                 _ => return
880             };
881             let res = mc.tables.qpath_res(qpath, pat.hir_id);
882             match res {
883                 Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_did) => {
884                     let variant_did = mc.tcx.parent(variant_ctor_did).unwrap();
885                     let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did);
886
887                     debug!("variantctor downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
888                     delegate.matched_pat(pat, &downcast_cmt, match_mode);
889                 }
890                 Res::Def(DefKind::Variant, variant_did) => {
891                     let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did);
892
893                     debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat);
894                     delegate.matched_pat(pat, &downcast_cmt, match_mode);
895                 }
896                 Res::Def(DefKind::Struct, _)
897                 | Res::Def(DefKind::Ctor(..), _)
898                 | Res::Def(DefKind::Union, _)
899                 | Res::Def(DefKind::TyAlias, _)
900                 | Res::Def(DefKind::AssocTy, _)
901                 | Res::SelfTy(..) => {
902                     debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat);
903                     delegate.matched_pat(pat, &cmt_pat, match_mode);
904                 }
905                 _ => {}
906             }
907         }));
908     }
909
910     fn walk_captures(&mut self, closure_expr: &hir::Expr, fn_decl_span: Span) {
911         debug!("walk_captures({:?})", closure_expr);
912
913         let closure_def_id = self.tcx().hir().local_def_id(closure_expr.hir_id);
914         if let Some(upvars) = self.tcx().upvars(closure_def_id) {
915             for (&var_id, upvar) in upvars.iter() {
916                 let upvar_id = ty::UpvarId {
917                     var_path: ty::UpvarPath { hir_id: var_id },
918                     closure_expr_id: closure_def_id.to_local(),
919                 };
920                 let upvar_capture = self.mc.tables.upvar_capture(upvar_id);
921                 let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id,
922                                                                    fn_decl_span,
923                                                                    var_id));
924                 match upvar_capture {
925                     ty::UpvarCapture::ByValue => {
926                         let mode = copy_or_move(&self.mc,
927                                                 self.param_env,
928                                                 &cmt_var,
929                                                 CaptureMove);
930                         self.delegate.consume(closure_expr.hir_id, upvar.span, &cmt_var, mode);
931                     }
932                     ty::UpvarCapture::ByRef(upvar_borrow) => {
933                         self.delegate.borrow(closure_expr.hir_id,
934                                              fn_decl_span,
935                                              &cmt_var,
936                                              upvar_borrow.region,
937                                              upvar_borrow.kind,
938                                              ClosureCapture(upvar.span));
939                     }
940                 }
941             }
942         }
943     }
944
945     fn cat_captured_var(&mut self,
946                         closure_hir_id: hir::HirId,
947                         closure_span: Span,
948                         var_id: hir::HirId)
949                         -> mc::McResult<mc::cmt_<'tcx>> {
950         // Create the cmt for the variable being borrowed, from the
951         // perspective of the creator (parent) of the closure.
952         let var_ty = self.mc.node_ty(var_id)?;
953         self.mc.cat_res(closure_hir_id, closure_span, var_ty, Res::Local(var_id))
954     }
955 }
956
957 fn copy_or_move<'a, 'tcx>(
958     mc: &mc::MemCategorizationContext<'a, 'tcx>,
959     param_env: ty::ParamEnv<'tcx>,
960     cmt: &mc::cmt_<'tcx>,
961     move_reason: MoveReason,
962 ) -> ConsumeMode {
963     if !mc.type_is_copy_modulo_regions(param_env, cmt.ty, cmt.span) {
964         Move(move_reason)
965     } else {
966         Copy
967     }
968 }