]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/expr_use_visitor.rs
Add a doctest for the std::string::as_string method.
[rust.git] / src / librustc / middle / expr_use_visitor.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A different sort of visitor for walking fn bodies.  Unlike the
12 //! normal visitor, which just walks the entire body in one shot, the
13 //! `ExprUseVisitor` determines how expressions are being used.
14
15 pub use self::MutateMode::*;
16 pub use self::LoanCause::*;
17 pub use self::ConsumeMode::*;
18 pub use self::MoveReason::*;
19 pub use self::MatchMode::*;
20 use self::TrackMatchMode::*;
21 use self::OverloadedCallType::*;
22
23 use middle::{def, region, pat_util};
24 use middle::mem_categorization as mc;
25 use middle::mem_categorization::Typer;
26 use middle::ty::{mod, Ty};
27 use middle::ty::{MethodCall, MethodObject, MethodTraitObject};
28 use middle::ty::{MethodOrigin, MethodParam, MethodTypeParam};
29 use middle::ty::{MethodStatic, MethodStaticUnboxedClosure};
30 use util::ppaux::Repr;
31
32 use syntax::ast;
33 use syntax::ptr::P;
34 use syntax::codemap::Span;
35
36 ///////////////////////////////////////////////////////////////////////////
37 // The Delegate trait
38
39 /// This trait defines the callbacks you can expect to receive when
40 /// employing the ExprUseVisitor.
41 pub trait Delegate<'tcx> {
42     // The value found at `cmt` is either copied or moved, depending
43     // on mode.
44     fn consume(&mut self,
45                consume_id: ast::NodeId,
46                consume_span: Span,
47                cmt: mc::cmt<'tcx>,
48                mode: ConsumeMode);
49
50     // The value found at `cmt` has been determined to match the
51     // pattern binding `matched_pat`, and its subparts are being
52     // copied or moved depending on `mode`.  Note that `matched_pat`
53     // is called on all variant/structs in the pattern (i.e., the
54     // interior nodes of the pattern's tree structure) while
55     // consume_pat is called on the binding identifiers in the pattern
56     // (which are leaves of the pattern's tree structure).
57     //
58     // Note that variants/structs and identifiers are disjoint; thus
59     // `matched_pat` and `consume_pat` are never both called on the
60     // same input pattern structure (though of `consume_pat` can be
61     // called on a subpart of an input passed to `matched_pat).
62     fn matched_pat(&mut self,
63                    matched_pat: &ast::Pat,
64                    cmt: mc::cmt<'tcx>,
65                    mode: MatchMode);
66
67     // The value found at `cmt` is either copied or moved via the
68     // pattern binding `consume_pat`, depending on mode.
69     fn consume_pat(&mut self,
70                    consume_pat: &ast::Pat,
71                    cmt: mc::cmt<'tcx>,
72                    mode: ConsumeMode);
73
74     // The value found at `borrow` is being borrowed at the point
75     // `borrow_id` for the region `loan_region` with kind `bk`.
76     fn borrow(&mut self,
77               borrow_id: ast::NodeId,
78               borrow_span: Span,
79               cmt: mc::cmt<'tcx>,
80               loan_region: ty::Region,
81               bk: ty::BorrowKind,
82               loan_cause: LoanCause);
83
84     // The local variable `id` is declared but not initialized.
85     fn decl_without_init(&mut self,
86                          id: ast::NodeId,
87                          span: Span);
88
89     // The path at `cmt` is being assigned to.
90     fn mutate(&mut self,
91               assignment_id: ast::NodeId,
92               assignment_span: Span,
93               assignee_cmt: mc::cmt<'tcx>,
94               mode: MutateMode);
95 }
96
97 #[deriving(PartialEq, Show)]
98 pub enum LoanCause {
99     ClosureCapture(Span),
100     AddrOf,
101     AutoRef,
102     RefBinding,
103     OverloadedOperator,
104     ClosureInvocation,
105     ForLoop,
106     MatchDiscriminant
107 }
108
109 #[deriving(PartialEq, Show)]
110 pub enum ConsumeMode {
111     Copy,                // reference to x where x has a type that copies
112     Move(MoveReason),    // reference to x where x has a type that moves
113 }
114
115 #[deriving(PartialEq,Show)]
116 pub enum MoveReason {
117     DirectRefMove,
118     PatBindingMove,
119     CaptureMove,
120 }
121
122 #[deriving(PartialEq,Show)]
123 pub enum MatchMode {
124     NonBindingMatch,
125     BorrowingMatch,
126     CopyingMatch,
127     MovingMatch,
128 }
129
130 #[deriving(PartialEq,Show)]
131 enum TrackMatchMode<T> {
132     Unknown, Definite(MatchMode), Conflicting,
133 }
134
135 impl<T> TrackMatchMode<T> {
136     // Builds up the whole match mode for a pattern from its constituent
137     // parts.  The lattice looks like this:
138     //
139     //          Conflicting
140     //            /     \
141     //           /       \
142     //      Borrowing   Moving
143     //           \       /
144     //            \     /
145     //            Copying
146     //               |
147     //          NonBinding
148     //               |
149     //            Unknown
150     //
151     // examples:
152     //
153     // * `(_, some_int)` pattern is Copying, since
154     //   NonBinding + Copying => Copying
155     //
156     // * `(some_int, some_box)` pattern is Moving, since
157     //   Copying + Moving => Moving
158     //
159     // * `(ref x, some_box)` pattern is Conflicting, since
160     //   Borrowing + Moving => Conflicting
161     //
162     // Note that the `Unknown` and `Conflicting` states are
163     // represented separately from the other more interesting
164     // `Definite` states, which simplifies logic here somewhat.
165     fn lub(&mut self, mode: MatchMode) {
166         *self = match (*self, mode) {
167             // Note that clause order below is very significant.
168             (Unknown, new) => Definite(new),
169             (Definite(old), new) if old == new => Definite(old),
170
171             (Definite(old), NonBindingMatch) => Definite(old),
172             (Definite(NonBindingMatch), new) => Definite(new),
173
174             (Definite(old), CopyingMatch) => Definite(old),
175             (Definite(CopyingMatch), new) => Definite(new),
176
177             (Definite(_), _) => Conflicting,
178             (Conflicting, _) => *self,
179         };
180     }
181
182     fn match_mode(&self) -> MatchMode {
183         match *self {
184             Unknown => NonBindingMatch,
185             Definite(mode) => mode,
186             Conflicting => {
187                 // Conservatively return MovingMatch to let the
188                 // compiler continue to make progress.
189                 MovingMatch
190             }
191         }
192     }
193 }
194
195 #[deriving(PartialEq,Show)]
196 pub enum MutateMode {
197     Init,
198     JustWrite,    // x = y
199     WriteAndRead, // x += y
200 }
201
202 enum OverloadedCallType {
203     FnOverloadedCall,
204     FnMutOverloadedCall,
205     FnOnceOverloadedCall,
206 }
207
208 impl OverloadedCallType {
209     fn from_trait_id(tcx: &ty::ctxt, trait_id: ast::DefId)
210                      -> OverloadedCallType {
211         for &(maybe_function_trait, overloaded_call_type) in [
212             (tcx.lang_items.fn_once_trait(), FnOnceOverloadedCall),
213             (tcx.lang_items.fn_mut_trait(), FnMutOverloadedCall),
214             (tcx.lang_items.fn_trait(), FnOverloadedCall)
215         ].iter() {
216             match maybe_function_trait {
217                 Some(function_trait) if function_trait == trait_id => {
218                     return overloaded_call_type
219                 }
220                 _ => continue,
221             }
222         }
223
224         tcx.sess.bug("overloaded call didn't map to known function trait")
225     }
226
227     fn from_method_id(tcx: &ty::ctxt, method_id: ast::DefId)
228                       -> OverloadedCallType {
229         let method_descriptor = match ty::impl_or_trait_item(tcx, method_id) {
230             ty::MethodTraitItem(ref method_descriptor) => {
231                 (*method_descriptor).clone()
232             }
233             ty::TypeTraitItem(_) => {
234                 tcx.sess.bug("overloaded call method wasn't in method map")
235             }
236         };
237         let impl_id = match method_descriptor.container {
238             ty::TraitContainer(_) => {
239                 tcx.sess.bug("statically resolved overloaded call method \
240                               belonged to a trait?!")
241             }
242             ty::ImplContainer(impl_id) => impl_id,
243         };
244         let trait_ref = match ty::impl_trait_ref(tcx, impl_id) {
245             None => {
246                 tcx.sess.bug("statically resolved overloaded call impl \
247                               didn't implement a trait?!")
248             }
249             Some(ref trait_ref) => (*trait_ref).clone(),
250         };
251         OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
252     }
253
254     fn from_unboxed_closure(tcx: &ty::ctxt, closure_did: ast::DefId)
255                             -> OverloadedCallType {
256         let trait_did =
257             tcx.unboxed_closures
258                .borrow()
259                .get(&closure_did)
260                .expect("OverloadedCallType::from_unboxed_closure: didn't \
261                         find closure id")
262                .kind
263                .trait_did(tcx);
264         OverloadedCallType::from_trait_id(tcx, trait_did)
265     }
266
267     fn from_method_origin(tcx: &ty::ctxt, origin: &MethodOrigin)
268                           -> OverloadedCallType {
269         match *origin {
270             MethodStatic(def_id) => {
271                 OverloadedCallType::from_method_id(tcx, def_id)
272             }
273             MethodStaticUnboxedClosure(def_id) => {
274                 OverloadedCallType::from_unboxed_closure(tcx, def_id)
275             }
276             MethodTypeParam(MethodParam { ref trait_ref, .. }) |
277             MethodTraitObject(MethodObject { ref trait_ref, .. }) => {
278                 OverloadedCallType::from_trait_id(tcx, trait_ref.def_id)
279             }
280         }
281     }
282 }
283
284 ///////////////////////////////////////////////////////////////////////////
285 // The ExprUseVisitor type
286 //
287 // This is the code that actually walks the tree. Like
288 // mem_categorization, it requires a TYPER, which is a type that
289 // supplies types from the tree. After type checking is complete, you
290 // can just use the tcx as the typer.
291
292 pub struct ExprUseVisitor<'d,'t,'tcx,TYPER:'t> {
293     typer: &'t TYPER,
294     mc: mc::MemCategorizationContext<'t,TYPER>,
295     delegate: &'d mut (Delegate<'tcx>+'d),
296 }
297
298 // If the TYPER results in an error, it's because the type check
299 // failed (or will fail, when the error is uncovered and reported
300 // during writeback). In this case, we just ignore this part of the
301 // code.
302 //
303 // Note that this macro appears similar to try!(), but, unlike try!(),
304 // it does not propagate the error.
305 macro_rules! return_if_err(
306     ($inp: expr) => (
307         match $inp {
308             Ok(v) => v,
309             Err(()) => return
310         }
311     )
312 )
313
314 impl<'d,'t,'tcx,TYPER:mc::Typer<'tcx>> ExprUseVisitor<'d,'t,'tcx,TYPER> {
315     pub fn new(delegate: &'d mut Delegate<'tcx>,
316                typer: &'t TYPER)
317                -> ExprUseVisitor<'d,'t,'tcx,TYPER> {
318         ExprUseVisitor { typer: typer,
319                          mc: mc::MemCategorizationContext::new(typer),
320                          delegate: delegate }
321     }
322
323     pub fn walk_fn(&mut self,
324                    decl: &ast::FnDecl,
325                    body: &ast::Block) {
326         self.walk_arg_patterns(decl, body);
327         self.walk_block(body);
328     }
329
330     fn walk_arg_patterns(&mut self,
331                          decl: &ast::FnDecl,
332                          body: &ast::Block) {
333         for arg in decl.inputs.iter() {
334             let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id));
335
336             let fn_body_scope = region::CodeExtent::from_node_id(body.id);
337             let arg_cmt = self.mc.cat_rvalue(
338                 arg.id,
339                 arg.pat.span,
340                 ty::ReScope(fn_body_scope), // Args live only as long as the fn body.
341                 arg_ty);
342
343             self.walk_irrefutable_pat(arg_cmt, &*arg.pat);
344         }
345     }
346
347     fn tcx(&self) -> &'t ty::ctxt<'tcx> {
348         self.typer.tcx()
349     }
350
351     fn delegate_consume(&mut self,
352                         consume_id: ast::NodeId,
353                         consume_span: Span,
354                         cmt: mc::cmt<'tcx>) {
355         let mode = copy_or_move(self.tcx(), cmt.ty, DirectRefMove);
356         self.delegate.consume(consume_id, consume_span, cmt, mode);
357     }
358
359     fn consume_exprs(&mut self, exprs: &Vec<P<ast::Expr>>) {
360         for expr in exprs.iter() {
361             self.consume_expr(&**expr);
362         }
363     }
364
365     pub fn consume_expr(&mut self, expr: &ast::Expr) {
366         debug!("consume_expr(expr={})", expr.repr(self.tcx()));
367
368         let cmt = return_if_err!(self.mc.cat_expr(expr));
369         self.delegate_consume(expr.id, expr.span, cmt);
370         self.walk_expr(expr);
371     }
372
373     fn mutate_expr(&mut self,
374                    assignment_expr: &ast::Expr,
375                    expr: &ast::Expr,
376                    mode: MutateMode) {
377         let cmt = return_if_err!(self.mc.cat_expr(expr));
378         self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode);
379         self.walk_expr(expr);
380     }
381
382     fn borrow_expr(&mut self,
383                    expr: &ast::Expr,
384                    r: ty::Region,
385                    bk: ty::BorrowKind,
386                    cause: LoanCause) {
387         debug!("borrow_expr(expr={}, r={}, bk={})",
388                expr.repr(self.tcx()), r.repr(self.tcx()), bk.repr(self.tcx()));
389
390         let cmt = return_if_err!(self.mc.cat_expr(expr));
391         self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
392
393         // Note: Unlike consume, we can ignore ExprParen. cat_expr
394         // already skips over them, and walk will uncover any
395         // attachments or whatever.
396         self.walk_expr(expr)
397     }
398
399     fn select_from_expr(&mut self, expr: &ast::Expr) {
400         self.walk_expr(expr)
401     }
402
403     pub fn walk_expr(&mut self, expr: &ast::Expr) {
404         debug!("walk_expr(expr={})", expr.repr(self.tcx()));
405
406         self.walk_adjustment(expr);
407
408         match expr.node {
409             ast::ExprParen(ref subexpr) => {
410                 self.walk_expr(&**subexpr)
411             }
412
413             ast::ExprPath(..) => { }
414
415             ast::ExprUnary(ast::UnDeref, ref base) => {      // *base
416                 if !self.walk_overloaded_operator(expr, &**base, Vec::new()) {
417                     self.select_from_expr(&**base);
418                 }
419             }
420
421             ast::ExprField(ref base, _) => {         // base.f
422                 self.select_from_expr(&**base);
423             }
424
425             ast::ExprTupField(ref base, _) => {         // base.<n>
426                 self.select_from_expr(&**base);
427             }
428
429             ast::ExprIndex(ref lhs, ref rhs) => {       // lhs[rhs]
430                 if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs]) {
431                     self.select_from_expr(&**lhs);
432                     self.consume_expr(&**rhs);
433                 }
434             }
435
436             ast::ExprSlice(ref base, ref start, ref end, _) => {    // base[start..end]
437                 let args = match (start, end) {
438                     (&Some(ref e1), &Some(ref e2)) => vec![&**e1, &**e2],
439                     (&Some(ref e), &None) => vec![&**e],
440                     (&None, &Some(ref e)) => vec![&**e],
441                     (&None, &None) => Vec::new()
442                 };
443                 let overloaded = self.walk_overloaded_operator(expr, &**base, args);
444                 assert!(overloaded);
445             }
446
447             ast::ExprCall(ref callee, ref args) => {    // callee(args)
448                 self.walk_callee(expr, &**callee);
449                 self.consume_exprs(args);
450             }
451
452             ast::ExprMethodCall(_, _, ref args) => { // callee.m(args)
453                 self.consume_exprs(args);
454             }
455
456             ast::ExprStruct(_, ref fields, ref opt_with) => {
457                 self.walk_struct_expr(expr, fields, opt_with);
458             }
459
460             ast::ExprTup(ref exprs) => {
461                 self.consume_exprs(exprs);
462             }
463
464             ast::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => {
465                 self.consume_expr(&**cond_expr);
466                 self.walk_block(&**then_blk);
467                 for else_expr in opt_else_expr.iter() {
468                     self.consume_expr(&**else_expr);
469                 }
470             }
471
472             ast::ExprIfLet(..) => {
473                 self.tcx().sess.span_bug(expr.span, "non-desugared ExprIfLet");
474             }
475
476             ast::ExprMatch(ref discr, ref arms, _) => {
477                 let discr_cmt = return_if_err!(self.mc.cat_expr(&**discr));
478                 self.borrow_expr(&**discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant);
479
480                 // treatment of the discriminant is handled while walking the arms.
481                 for arm in arms.iter() {
482                     let mode = self.arm_move_mode(discr_cmt.clone(), arm);
483                     let mode = mode.match_mode();
484                     self.walk_arm(discr_cmt.clone(), arm, mode);
485                 }
486             }
487
488             ast::ExprVec(ref exprs) => {
489                 self.consume_exprs(exprs);
490             }
491
492             ast::ExprAddrOf(m, ref base) => {   // &base
493                 // make sure that the thing we are pointing out stays valid
494                 // for the lifetime `scope_r` of the resulting ptr:
495                 let expr_ty = ty::expr_ty(self.tcx(), expr);
496                 let r = ty::ty_region(self.tcx(), expr.span, expr_ty);
497                 let bk = ty::BorrowKind::from_mutbl(m);
498                 self.borrow_expr(&**base, r, bk, AddrOf);
499             }
500
501             ast::ExprInlineAsm(ref ia) => {
502                 for &(_, ref input) in ia.inputs.iter() {
503                     self.consume_expr(&**input);
504                 }
505
506                 for &(_, ref output, is_rw) in ia.outputs.iter() {
507                     self.mutate_expr(expr, &**output,
508                                            if is_rw { WriteAndRead } else { JustWrite });
509                 }
510             }
511
512             ast::ExprBreak(..) |
513             ast::ExprAgain(..) |
514             ast::ExprLit(..) => {}
515
516             ast::ExprLoop(ref blk, _) => {
517                 self.walk_block(&**blk);
518             }
519
520             ast::ExprWhile(ref cond_expr, ref blk, _) => {
521                 self.consume_expr(&**cond_expr);
522                 self.walk_block(&**blk);
523             }
524
525             ast::ExprWhileLet(..) => {
526                 self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
527             }
528
529             ast::ExprForLoop(ref pat, ref head, ref blk, _) => {
530                 // The pattern lives as long as the block.
531                 debug!("walk_expr for loop case: blk id={}", blk.id);
532                 self.consume_expr(&**head);
533
534                 // Fetch the type of the value that the iteration yields to
535                 // produce the pattern's categorized mutable type.
536                 let pattern_type = return_if_err!(self.typer.node_ty(pat.id));
537                 let blk_scope = region::CodeExtent::from_node_id(blk.id);
538                 let pat_cmt = self.mc.cat_rvalue(pat.id,
539                                                  pat.span,
540                                                  ty::ReScope(blk_scope),
541                                                  pattern_type);
542                 self.walk_irrefutable_pat(pat_cmt, &**pat);
543
544                 self.walk_block(&**blk);
545             }
546
547             ast::ExprUnary(_, ref lhs) => {
548                 if !self.walk_overloaded_operator(expr, &**lhs, Vec::new()) {
549                     self.consume_expr(&**lhs);
550                 }
551             }
552
553             ast::ExprBinary(_, ref lhs, ref rhs) => {
554                 if !self.walk_overloaded_operator(expr, &**lhs, vec![&**rhs]) {
555                     self.consume_expr(&**lhs);
556                     self.consume_expr(&**rhs);
557                 }
558             }
559
560             ast::ExprBlock(ref blk) => {
561                 self.walk_block(&**blk);
562             }
563
564             ast::ExprRet(ref opt_expr) => {
565                 for expr in opt_expr.iter() {
566                     self.consume_expr(&**expr);
567                 }
568             }
569
570             ast::ExprAssign(ref lhs, ref rhs) => {
571                 self.mutate_expr(expr, &**lhs, JustWrite);
572                 self.consume_expr(&**rhs);
573             }
574
575             ast::ExprCast(ref base, _) => {
576                 self.consume_expr(&**base);
577             }
578
579             ast::ExprAssignOp(_, ref lhs, ref rhs) => {
580                 // This will have to change if/when we support
581                 // overloaded operators for `+=` and so forth.
582                 self.mutate_expr(expr, &**lhs, WriteAndRead);
583                 self.consume_expr(&**rhs);
584             }
585
586             ast::ExprRepeat(ref base, ref count) => {
587                 self.consume_expr(&**base);
588                 self.consume_expr(&**count);
589             }
590
591             ast::ExprClosure(..) |
592             ast::ExprProc(..) => {
593                 self.walk_captures(expr)
594             }
595
596             ast::ExprBox(ref place, ref base) => {
597                 self.consume_expr(&**place);
598                 self.consume_expr(&**base);
599             }
600
601             ast::ExprMac(..) => {
602                 self.tcx().sess.span_bug(
603                     expr.span,
604                     "macro expression remains after expansion");
605             }
606         }
607     }
608
609     fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) {
610         let callee_ty = ty::expr_ty_adjusted(self.tcx(), callee);
611         debug!("walk_callee: callee={} callee_ty={}",
612                callee.repr(self.tcx()), callee_ty.repr(self.tcx()));
613         let call_scope = region::CodeExtent::from_node_id(call.id);
614         match callee_ty.sty {
615             ty::ty_bare_fn(..) => {
616                 self.consume_expr(callee);
617             }
618             ty::ty_closure(ref f) => {
619                 match f.onceness {
620                     ast::Many => {
621                         self.borrow_expr(callee,
622                                          ty::ReScope(call_scope),
623                                          ty::UniqueImmBorrow,
624                                          ClosureInvocation);
625                     }
626                     ast::Once => {
627                         self.consume_expr(callee);
628                     }
629                 }
630             }
631             _ => {
632                 let overloaded_call_type =
633                     match self.tcx()
634                               .method_map
635                               .borrow()
636                               .get(&MethodCall::expr(call.id)) {
637                     Some(ref method_callee) => {
638                         OverloadedCallType::from_method_origin(
639                             self.tcx(),
640                             &method_callee.origin)
641                     }
642                     None => {
643                         self.tcx().sess.span_bug(
644                             callee.span,
645                             format!("unexpected callee type {}",
646                                     callee_ty.repr(self.tcx())).as_slice())
647                     }
648                 };
649                 match overloaded_call_type {
650                     FnMutOverloadedCall => {
651                         self.borrow_expr(callee,
652                                          ty::ReScope(call_scope),
653                                          ty::MutBorrow,
654                                          ClosureInvocation);
655                     }
656                     FnOverloadedCall => {
657                         self.borrow_expr(callee,
658                                          ty::ReScope(call_scope),
659                                          ty::ImmBorrow,
660                                          ClosureInvocation);
661                     }
662                     FnOnceOverloadedCall => self.consume_expr(callee),
663                 }
664             }
665         }
666     }
667
668     fn walk_stmt(&mut self, stmt: &ast::Stmt) {
669         match stmt.node {
670             ast::StmtDecl(ref decl, _) => {
671                 match decl.node {
672                     ast::DeclLocal(ref local) => {
673                         self.walk_local(&**local);
674                     }
675
676                     ast::DeclItem(_) => {
677                         // we don't visit nested items in this visitor,
678                         // only the fn body we were given.
679                     }
680                 }
681             }
682
683             ast::StmtExpr(ref expr, _) |
684             ast::StmtSemi(ref expr, _) => {
685                 self.consume_expr(&**expr);
686             }
687
688             ast::StmtMac(..) => {
689                 self.tcx().sess.span_bug(stmt.span, "unexpanded stmt macro");
690             }
691         }
692     }
693
694     fn walk_local(&mut self, local: &ast::Local) {
695         match local.init {
696             None => {
697                 let delegate = &mut self.delegate;
698                 pat_util::pat_bindings(&self.typer.tcx().def_map, &*local.pat,
699                                        |_, id, span, _| {
700                     delegate.decl_without_init(id, span);
701                 })
702             }
703
704             Some(ref expr) => {
705                 // Variable declarations with
706                 // initializers are considered
707                 // "assigns", which is handled by
708                 // `walk_pat`:
709                 self.walk_expr(&**expr);
710                 let init_cmt = return_if_err!(self.mc.cat_expr(&**expr));
711                 self.walk_irrefutable_pat(init_cmt, &*local.pat);
712             }
713         }
714     }
715
716     /// Indicates that the value of `blk` will be consumed, meaning either copied or moved
717     /// depending on its type.
718     fn walk_block(&mut self, blk: &ast::Block) {
719         debug!("walk_block(blk.id={})", blk.id);
720
721         for stmt in blk.stmts.iter() {
722             self.walk_stmt(&**stmt);
723         }
724
725         for tail_expr in blk.expr.iter() {
726             self.consume_expr(&**tail_expr);
727         }
728     }
729
730     fn walk_struct_expr(&mut self,
731                         _expr: &ast::Expr,
732                         fields: &Vec<ast::Field>,
733                         opt_with: &Option<P<ast::Expr>>) {
734         // Consume the expressions supplying values for each field.
735         for field in fields.iter() {
736             self.consume_expr(&*field.expr);
737         }
738
739         let with_expr = match *opt_with {
740             Some(ref w) => &**w,
741             None => { return; }
742         };
743
744         let with_cmt = return_if_err!(self.mc.cat_expr(&*with_expr));
745
746         // Select just those fields of the `with`
747         // expression that will actually be used
748         let with_fields = match with_cmt.ty.sty {
749             ty::ty_struct(did, ref substs) => {
750                 ty::struct_fields(self.tcx(), did, substs)
751             }
752             _ => {
753                 self.tcx().sess.span_bug(
754                     with_expr.span,
755                     "with expression doesn't evaluate to a struct");
756             }
757         };
758
759         // Consume those fields of the with expression that are needed.
760         for with_field in with_fields.iter() {
761             if !contains_field_named(with_field, fields) {
762                 let cmt_field = self.mc.cat_field(&*with_expr,
763                                                   with_cmt.clone(),
764                                                   with_field.name,
765                                                   with_field.mt.ty);
766                 self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
767             }
768         }
769
770         // walk the with expression so that complex expressions
771         // are properly handled.
772         self.walk_expr(with_expr);
773
774         fn contains_field_named(field: &ty::field,
775                                 fields: &Vec<ast::Field>)
776                                 -> bool
777         {
778             fields.iter().any(
779                 |f| f.ident.node.name == field.name)
780         }
781     }
782
783     // Invoke the appropriate delegate calls for anything that gets
784     // consumed or borrowed as part of the automatic adjustment
785     // process.
786     fn walk_adjustment(&mut self, expr: &ast::Expr) {
787         let typer = self.typer;
788         match typer.adjustments().borrow().get(&expr.id) {
789             None => { }
790             Some(adjustment) => {
791                 match *adjustment {
792                     ty::AdjustAddEnv(..) => {
793                         // Creating a closure consumes the input and stores it
794                         // into the resulting rvalue.
795                         debug!("walk_adjustment(AutoAddEnv)");
796                         let cmt_unadjusted =
797                             return_if_err!(self.mc.cat_expr_unadjusted(expr));
798                         self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
799                     }
800                     ty::AdjustDerefRef(ty::AutoDerefRef {
801                         autoref: ref opt_autoref,
802                         autoderefs: n
803                     }) => {
804                         self.walk_autoderefs(expr, n);
805
806                         match *opt_autoref {
807                             None => { }
808                             Some(ref r) => {
809                                 self.walk_autoref(expr, r, n);
810                             }
811                         }
812                     }
813                 }
814             }
815         }
816     }
817
818     /// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have
819     /// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since
820     /// `deref()` is declared with `&self`, this is an autoref of `x`.
821     fn walk_autoderefs(&mut self,
822                        expr: &ast::Expr,
823                        autoderefs: uint) {
824         debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
825
826         for i in range(0, autoderefs) {
827             let deref_id = ty::MethodCall::autoderef(expr.id, i);
828             match self.typer.node_method_ty(deref_id) {
829                 None => {}
830                 Some(method_ty) => {
831                     let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
832                     let self_ty = ty::ty_fn_args(method_ty)[0];
833                     let (m, r) = match self_ty.sty {
834                         ty::ty_rptr(r, ref m) => (m.mutbl, r),
835                         _ => self.tcx().sess.span_bug(expr.span,
836                                 format!("bad overloaded deref type {}",
837                                     method_ty.repr(self.tcx())).as_slice())
838                     };
839                     let bk = ty::BorrowKind::from_mutbl(m);
840                     self.delegate.borrow(expr.id, expr.span, cmt,
841                                          r, bk, AutoRef);
842                 }
843             }
844         }
845     }
846
847     fn walk_autoref(&mut self,
848                     expr: &ast::Expr,
849                     autoref: &ty::AutoRef,
850                     n: uint) {
851         debug!("walk_autoref expr={}", expr.repr(self.tcx()));
852
853         // Match for unique trait coercions first, since we don't need the
854         // call to cat_expr_autoderefd.
855         match *autoref {
856             ty::AutoUnsizeUniq(ty::UnsizeVtable(..)) |
857             ty::AutoUnsize(ty::UnsizeVtable(..)) => {
858                 assert!(n == 1, format!("Expected exactly 1 deref with Uniq \
859                                          AutoRefs, found: {}", n));
860                 let cmt_unadjusted =
861                     return_if_err!(self.mc.cat_expr_unadjusted(expr));
862                 self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
863                 return;
864             }
865             _ => {}
866         }
867
868         let cmt_derefd = return_if_err!(
869             self.mc.cat_expr_autoderefd(expr, n));
870         debug!("walk_adjustment: cmt_derefd={}",
871                cmt_derefd.repr(self.tcx()));
872
873         match *autoref {
874             ty::AutoPtr(r, m, _) => {
875                 self.delegate.borrow(expr.id,
876                                      expr.span,
877                                      cmt_derefd,
878                                      r,
879                                      ty::BorrowKind::from_mutbl(m),
880                                      AutoRef);
881             }
882             ty::AutoUnsizeUniq(_) | ty::AutoUnsize(_) | ty::AutoUnsafe(..) => {}
883         }
884     }
885
886     fn walk_overloaded_operator(&mut self,
887                                 expr: &ast::Expr,
888                                 receiver: &ast::Expr,
889                                 rhs: Vec<&ast::Expr>)
890                                 -> bool
891     {
892         if !self.typer.is_method_call(expr.id) {
893             return false;
894         }
895
896         self.walk_expr(receiver);
897
898         // Arguments (but not receivers) to overloaded operator
899         // methods are implicitly autoref'd which sadly does not use
900         // adjustments, so we must hardcode the borrow here.
901
902         let r = ty::ReScope(region::CodeExtent::from_node_id(expr.id));
903         let bk = ty::ImmBorrow;
904
905         for &arg in rhs.iter() {
906             self.borrow_expr(arg, r, bk, OverloadedOperator);
907         }
908         return true;
909     }
910
911     fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm) -> TrackMatchMode<Span> {
912         let mut mode = Unknown;
913         for pat in arm.pats.iter() {
914             self.determine_pat_move_mode(discr_cmt.clone(), &**pat, &mut mode);
915         }
916         mode
917     }
918
919     fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &ast::Arm, mode: MatchMode) {
920         for pat in arm.pats.iter() {
921             self.walk_pat(discr_cmt.clone(), &**pat, mode);
922         }
923
924         for guard in arm.guard.iter() {
925             self.consume_expr(&**guard);
926         }
927
928         self.consume_expr(&*arm.body);
929     }
930
931     /// Walks an pat that occurs in isolation (i.e. top-level of fn
932     /// arg or let binding.  *Not* a match arm or nested pat.)
933     fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &ast::Pat) {
934         let mut mode = Unknown;
935         self.determine_pat_move_mode(cmt_discr.clone(), pat, &mut mode);
936         let mode = mode.match_mode();
937         self.walk_pat(cmt_discr, pat, mode);
938     }
939
940     /// Identifies any bindings within `pat` and accumulates within
941     /// `mode` whether the overall pattern/match structure is a move,
942     /// copy, or borrow.
943     fn determine_pat_move_mode(&mut self,
944                                cmt_discr: mc::cmt<'tcx>,
945                                pat: &ast::Pat,
946                                mode: &mut TrackMatchMode<Span>) {
947         debug!("determine_pat_move_mode cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
948                pat.repr(self.tcx()));
949         return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| {
950             let tcx = self.typer.tcx();
951             let def_map = &self.typer.tcx().def_map;
952             if pat_util::pat_is_binding(def_map, pat) {
953                 match pat.node {
954                     ast::PatIdent(ast::BindByRef(_), _, _) =>
955                         mode.lub(BorrowingMatch),
956                     ast::PatIdent(ast::BindByValue(_), _, _) => {
957                         match copy_or_move(tcx, cmt_pat.ty, PatBindingMove) {
958                             Copy => mode.lub(CopyingMatch),
959                             Move(_) => mode.lub(MovingMatch),
960                         }
961                     }
962                     _ => {
963                         tcx.sess.span_bug(
964                             pat.span,
965                             "binding pattern not an identifier");
966                     }
967                 }
968             }
969         }));
970     }
971
972     /// The core driver for walking a pattern; `match_mode` must be
973     /// established up front, e.g. via `determine_pat_move_mode` (see
974     /// also `walk_irrefutable_pat` for patterns that stand alone).
975     fn walk_pat(&mut self,
976                 cmt_discr: mc::cmt<'tcx>,
977                 pat: &ast::Pat,
978                 match_mode: MatchMode) {
979         debug!("walk_pat cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
980                pat.repr(self.tcx()));
981
982         let mc = &self.mc;
983         let typer = self.typer;
984         let tcx = typer.tcx();
985         let def_map = &self.typer.tcx().def_map;
986         let delegate = &mut self.delegate;
987
988         return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| {
989             if pat_util::pat_is_binding(def_map, pat) {
990                 let tcx = typer.tcx();
991
992                 debug!("binding cmt_pat={} pat={} match_mode={}",
993                        cmt_pat.repr(tcx),
994                        pat.repr(tcx),
995                        match_mode);
996
997                 // pat_ty: the type of the binding being produced.
998                 let pat_ty = return_if_err!(typer.node_ty(pat.id));
999
1000                 // Each match binding is effectively an assignment to the
1001                 // binding being produced.
1002                 let def = def_map.borrow()[pat.id].clone();
1003                 match mc.cat_def(pat.id, pat.span, pat_ty, def) {
1004                     Ok(binding_cmt) => {
1005                         delegate.mutate(pat.id, pat.span, binding_cmt, Init);
1006                     }
1007                     Err(_) => { }
1008                 }
1009
1010                 // It is also a borrow or copy/move of the value being matched.
1011                 match pat.node {
1012                     ast::PatIdent(ast::BindByRef(m), _, _) => {
1013                         let (r, bk) = {
1014                             (ty::ty_region(tcx, pat.span, pat_ty),
1015                              ty::BorrowKind::from_mutbl(m))
1016                         };
1017                         delegate.borrow(pat.id, pat.span, cmt_pat,
1018                                              r, bk, RefBinding);
1019                     }
1020                     ast::PatIdent(ast::BindByValue(_), _, _) => {
1021                         let mode = copy_or_move(typer.tcx(), cmt_pat.ty, PatBindingMove);
1022                         debug!("walk_pat binding consuming pat");
1023                         delegate.consume_pat(pat, cmt_pat, mode);
1024                     }
1025                     _ => {
1026                         typer.tcx().sess.span_bug(
1027                             pat.span,
1028                             "binding pattern not an identifier");
1029                     }
1030                 }
1031             } else {
1032                 match pat.node {
1033                     ast::PatVec(_, Some(ref slice_pat), _) => {
1034                         // The `slice_pat` here creates a slice into
1035                         // the original vector.  This is effectively a
1036                         // borrow of the elements of the vector being
1037                         // matched.
1038
1039                         let (slice_cmt, slice_mutbl, slice_r) = {
1040                             match mc.cat_slice_pattern(cmt_pat, &**slice_pat) {
1041                                 Ok(v) => v,
1042                                 Err(()) => {
1043                                     tcx.sess.span_bug(slice_pat.span,
1044                                                       "Err from mc")
1045                                 }
1046                             }
1047                         };
1048
1049                         // Note: We declare here that the borrow
1050                         // occurs upon entering the `[...]`
1051                         // pattern. This implies that something like
1052                         // `[a, ..b]` where `a` is a move is illegal,
1053                         // because the borrow is already in effect.
1054                         // In fact such a move would be safe-ish, but
1055                         // it effectively *requires* that we use the
1056                         // nulling out semantics to indicate when a
1057                         // value has been moved, which we are trying
1058                         // to move away from.  Otherwise, how can we
1059                         // indicate that the first element in the
1060                         // vector has been moved?  Eventually, we
1061                         // could perhaps modify this rule to permit
1062                         // `[..a, b]` where `b` is a move, because in
1063                         // that case we can adjust the length of the
1064                         // original vec accordingly, but we'd have to
1065                         // make trans do the right thing, and it would
1066                         // only work for `~` vectors. It seems simpler
1067                         // to just require that people call
1068                         // `vec.pop()` or `vec.unshift()`.
1069                         let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
1070                         delegate.borrow(pat.id, pat.span,
1071                                         slice_cmt, slice_r,
1072                                         slice_bk, RefBinding);
1073                     }
1074                     _ => { }
1075                 }
1076             }
1077         }));
1078
1079         // Do a second pass over the pattern, calling `matched_pat` on
1080         // the interior nodes (enum variants and structs), as opposed
1081         // to the above loop's visit of than the bindings that form
1082         // the leaves of the pattern tree structure.
1083         return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
1084             let def_map = def_map.borrow();
1085             let tcx = typer.tcx();
1086
1087             match pat.node {
1088                 ast::PatEnum(_, _) | ast::PatIdent(_, _, None) | ast::PatStruct(..) => {
1089                     match def_map.get(&pat.id) {
1090                         None => {
1091                             // no definition found: pat is not a
1092                             // struct or enum pattern.
1093                         }
1094
1095                         Some(&def::DefVariant(enum_did, variant_did, _is_struct)) => {
1096                             let downcast_cmt =
1097                                 if ty::enum_is_univariant(tcx, enum_did) {
1098                                     cmt_pat
1099                                 } else {
1100                                     let cmt_pat_ty = cmt_pat.ty;
1101                                     mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did)
1102                                 };
1103
1104                             debug!("variant downcast_cmt={} pat={}",
1105                                    downcast_cmt.repr(tcx),
1106                                    pat.repr(tcx));
1107
1108                             delegate.matched_pat(pat, downcast_cmt, match_mode);
1109                         }
1110
1111                         Some(&def::DefStruct(..)) | Some(&def::DefTy(_, false)) => {
1112                             // A struct (in either the value or type
1113                             // namespace; we encounter the former on
1114                             // e.g. patterns for unit structs).
1115
1116                             debug!("struct cmt_pat={} pat={}",
1117                                    cmt_pat.repr(tcx),
1118                                    pat.repr(tcx));
1119
1120                             delegate.matched_pat(pat, cmt_pat, match_mode);
1121                         }
1122
1123                         Some(&def::DefConst(..)) |
1124                         Some(&def::DefLocal(..)) => {
1125                             // This is a leaf (i.e. identifier binding
1126                             // or constant value to match); thus no
1127                             // `matched_pat` call.
1128                         }
1129
1130                         Some(def @ &def::DefTy(_, true)) => {
1131                             // An enum's type -- should never be in a
1132                             // pattern.
1133
1134                             let msg = format!("Pattern has unexpected type: {}", def);
1135                             tcx.sess.span_bug(pat.span, msg.as_slice())
1136                         }
1137
1138                         Some(def) => {
1139                             // Remaining cases are e.g. DefFn, to
1140                             // which identifiers within patterns
1141                             // should not resolve.
1142
1143                             let msg = format!("Pattern has unexpected def: {}", def);
1144                             tcx.sess.span_bug(pat.span, msg.as_slice())
1145                         }
1146                     }
1147                 }
1148
1149                 ast::PatIdent(_, _, Some(_)) => {
1150                     // Do nothing; this is a binding (not a enum
1151                     // variant or struct), and the cat_pattern call
1152                     // will visit the substructure recursively.
1153                 }
1154
1155                 ast::PatWild(_) | ast::PatTup(..) | ast::PatBox(..) |
1156                 ast::PatRegion(..) | ast::PatLit(..) | ast::PatRange(..) |
1157                 ast::PatVec(..) | ast::PatMac(..) => {
1158                     // Similarly, each of these cases does not
1159                     // correspond to a enum variant or struct, so we
1160                     // do not do any `matched_pat` calls for these
1161                     // cases either.
1162                 }
1163             }
1164         }));
1165     }
1166
1167     fn walk_captures(&mut self, closure_expr: &ast::Expr) {
1168         debug!("walk_captures({})", closure_expr.repr(self.tcx()));
1169
1170         let tcx = self.typer.tcx();
1171         ty::with_freevars(tcx, closure_expr.id, |freevars| {
1172             match self.tcx().capture_mode(closure_expr.id) {
1173                 ast::CaptureByRef => {
1174                     self.walk_by_ref_captures(closure_expr, freevars);
1175                 }
1176                 ast::CaptureByValue => {
1177                     self.walk_by_value_captures(closure_expr, freevars);
1178                 }
1179             }
1180         });
1181     }
1182
1183     fn walk_by_ref_captures(&mut self,
1184                             closure_expr: &ast::Expr,
1185                             freevars: &[ty::Freevar]) {
1186         for freevar in freevars.iter() {
1187             let id_var = freevar.def.def_id().node;
1188             let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
1189                                                                closure_expr.span,
1190                                                                freevar.def));
1191
1192             // Lookup the kind of borrow the callee requires, as
1193             // inferred by regionbk
1194             let upvar_id = ty::UpvarId { var_id: id_var,
1195                                          closure_expr_id: closure_expr.id };
1196             let upvar_borrow = self.tcx().upvar_borrow_map.borrow()[upvar_id].clone();
1197
1198             self.delegate.borrow(closure_expr.id,
1199                                  closure_expr.span,
1200                                  cmt_var,
1201                                  upvar_borrow.region,
1202                                  upvar_borrow.kind,
1203                                  ClosureCapture(freevar.span));
1204         }
1205     }
1206
1207     fn walk_by_value_captures(&mut self,
1208                               closure_expr: &ast::Expr,
1209                               freevars: &[ty::Freevar]) {
1210         for freevar in freevars.iter() {
1211             let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
1212                                                                closure_expr.span,
1213                                                                freevar.def));
1214             let mode = copy_or_move(self.tcx(), cmt_var.ty, CaptureMove);
1215             self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
1216         }
1217     }
1218
1219     fn cat_captured_var(&mut self,
1220                         closure_id: ast::NodeId,
1221                         closure_span: Span,
1222                         upvar_def: def::Def)
1223                         -> mc::McResult<mc::cmt<'tcx>> {
1224         // Create the cmt for the variable being borrowed, from the
1225         // caller's perspective
1226         let var_id = upvar_def.def_id().node;
1227         let var_ty = try!(self.typer.node_ty(var_id));
1228         self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
1229     }
1230 }
1231
1232 fn copy_or_move<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>,
1233                       move_reason: MoveReason) -> ConsumeMode {
1234     if ty::type_moves_by_default(tcx, ty) { Move(move_reason) } else { Copy }
1235 }
1236