]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/expr_use_visitor.rs
librustc: Implement overloading for the call operator behind a feature
[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 /*!
12  * A different sort of visitor for walking fn bodies.  Unlike the
13  * normal visitor, which just walks the entire body in one shot, the
14  * `ExprUseVisitor` determines how expressions are being used.
15  */
16
17 use mc = middle::mem_categorization;
18 use middle::def;
19 use middle::freevars;
20 use middle::pat_util;
21 use middle::ty;
22 use middle::typeck::MethodCall;
23 use middle::typeck;
24 use syntax::ast;
25 use syntax::codemap::{Span};
26 use util::ppaux::Repr;
27
28 ///////////////////////////////////////////////////////////////////////////
29 // The Delegate trait
30
31 /// This trait defines the callbacks you can expect to receive when
32 /// employing the ExprUseVisitor.
33 pub trait Delegate {
34     // The value found at `cmt` is either copied or moved, depending
35     // on mode.
36     fn consume(&mut self,
37                consume_id: ast::NodeId,
38                consume_span: Span,
39                cmt: mc::cmt,
40                mode: ConsumeMode);
41
42     // The value found at `cmt` is either copied or moved via the
43     // pattern binding `consume_pat`, depending on mode.
44     fn consume_pat(&mut self,
45                    consume_pat: &ast::Pat,
46                    cmt: mc::cmt,
47                    mode: ConsumeMode);
48
49     // The value found at `borrow` is being borrowed at the point
50     // `borrow_id` for the region `loan_region` with kind `bk`.
51     fn borrow(&mut self,
52               borrow_id: ast::NodeId,
53               borrow_span: Span,
54               cmt: mc::cmt,
55               loan_region: ty::Region,
56               bk: ty::BorrowKind,
57               loan_cause: LoanCause);
58
59     // The local variable `id` is declared but not initialized.
60     fn decl_without_init(&mut self,
61                          id: ast::NodeId,
62                          span: Span);
63
64     // The path at `cmt` is being assigned to.
65     fn mutate(&mut self,
66               assignment_id: ast::NodeId,
67               assignment_span: Span,
68               assignee_cmt: mc::cmt,
69               mode: MutateMode);
70 }
71
72 #[deriving(PartialEq)]
73 pub enum LoanCause {
74     ClosureCapture(Span),
75     AddrOf,
76     AutoRef,
77     RefBinding,
78     OverloadedOperator,
79     ClosureInvocation
80 }
81
82 #[deriving(PartialEq,Show)]
83 pub enum ConsumeMode {
84     Copy,                // reference to x where x has a type that copies
85     Move(MoveReason),    // reference to x where x has a type that moves
86 }
87
88 #[deriving(PartialEq,Show)]
89 pub enum MoveReason {
90     DirectRefMove,
91     PatBindingMove,
92     CaptureMove,
93 }
94
95 #[deriving(PartialEq,Show)]
96 pub enum MutateMode {
97     Init,
98     JustWrite,    // x = y
99     WriteAndRead, // x += y
100 }
101
102 ///////////////////////////////////////////////////////////////////////////
103 // The ExprUseVisitor type
104 //
105 // This is the code that actually walks the tree. Like
106 // mem_categorization, it requires a TYPER, which is a type that
107 // supplies types from the tree. After type checking is complete, you
108 // can just use the tcx as the typer.
109
110 pub struct ExprUseVisitor<'d,'t,TYPER> {
111     typer: &'t TYPER,
112     mc: mc::MemCategorizationContext<'t,TYPER>,
113     delegate: &'d mut Delegate,
114 }
115
116 // If the TYPER results in an error, it's because the type check
117 // failed (or will fail, when the error is uncovered and reported
118 // during writeback). In this case, we just ignore this part of the
119 // code.
120 //
121 // Note that this macro appears similar to try!(), but, unlike try!(),
122 // it does not propagate the error.
123 macro_rules! return_if_err(
124     ($inp: expr) => (
125         match $inp {
126             Ok(v) => v,
127             Err(()) => return
128         }
129     )
130 )
131
132 impl<'d,'t,TYPER:mc::Typer> ExprUseVisitor<'d,'t,TYPER> {
133     pub fn new(delegate: &'d mut Delegate,
134                typer: &'t TYPER)
135                -> ExprUseVisitor<'d,'t,TYPER> {
136         ExprUseVisitor { typer: typer,
137                          mc: mc::MemCategorizationContext::new(typer),
138                          delegate: delegate }
139     }
140
141     pub fn walk_fn(&mut self,
142                    decl: &ast::FnDecl,
143                    body: &ast::Block) {
144         self.walk_arg_patterns(decl, body);
145         self.walk_block(body);
146     }
147
148     fn walk_arg_patterns(&mut self,
149                          decl: &ast::FnDecl,
150                          body: &ast::Block) {
151         for arg in decl.inputs.iter() {
152             let arg_ty = ty::node_id_to_type(self.tcx(), arg.pat.id);
153
154             let arg_cmt = self.mc.cat_rvalue(
155                 arg.id,
156                 arg.pat.span,
157                 ty::ReScope(body.id), // Args live only as long as the fn body.
158                 arg_ty);
159
160             self.walk_pat(arg_cmt, arg.pat);
161         }
162     }
163
164     fn tcx<'a>(&'a self) -> &'a ty::ctxt {
165         self.typer.tcx()
166     }
167
168     fn delegate_consume(&mut self,
169                         consume_id: ast::NodeId,
170                         consume_span: Span,
171                         cmt: mc::cmt) {
172         let mode = copy_or_move(self.tcx(), cmt.ty, DirectRefMove);
173         self.delegate.consume(consume_id, consume_span, cmt, mode);
174     }
175
176     fn consume_exprs(&mut self, exprs: &Vec<@ast::Expr>) {
177         for &expr in exprs.iter() {
178             self.consume_expr(expr);
179         }
180     }
181
182     fn consume_expr(&mut self, expr: &ast::Expr) {
183         debug!("consume_expr(expr={})", expr.repr(self.tcx()));
184
185         let cmt = return_if_err!(self.mc.cat_expr(expr));
186         self.delegate_consume(expr.id, expr.span, cmt);
187
188         match expr.node {
189             ast::ExprParen(subexpr) => {
190                 // Argh but is ExprParen horrible. So, if we consume
191                 // `(x)`, that generally is also consuming `x`, UNLESS
192                 // there are adjustments on the `(x)` expression
193                 // (e.g., autoderefs and autorefs).
194                 if self.typer.adjustments().borrow().contains_key(&expr.id) {
195                     self.walk_expr(expr);
196                 } else {
197                     self.consume_expr(subexpr);
198                 }
199             }
200
201             _ => {
202                 self.walk_expr(expr)
203             }
204         }
205     }
206
207     fn mutate_expr(&mut self,
208                    assignment_expr: &ast::Expr,
209                    expr: &ast::Expr,
210                    mode: MutateMode) {
211         let cmt = return_if_err!(self.mc.cat_expr(expr));
212         self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode);
213         self.walk_expr(expr);
214     }
215
216     fn borrow_expr(&mut self,
217                    expr: &ast::Expr,
218                    r: ty::Region,
219                    bk: ty::BorrowKind,
220                    cause: LoanCause) {
221         debug!("borrow_expr(expr={}, r={}, bk={})",
222                expr.repr(self.tcx()), r.repr(self.tcx()), bk.repr(self.tcx()));
223
224         let cmt = return_if_err!(self.mc.cat_expr(expr));
225         self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause);
226
227         // Note: Unlike consume, we can ignore ExprParen. cat_expr
228         // already skips over them, and walk will uncover any
229         // attachments or whatever.
230         self.walk_expr(expr)
231     }
232
233     fn select_from_expr(&mut self, expr: &ast::Expr) {
234         self.walk_expr(expr)
235     }
236
237     fn walk_expr(&mut self, expr: &ast::Expr) {
238         debug!("walk_expr(expr={})", expr.repr(self.tcx()));
239
240         self.walk_adjustment(expr);
241
242         match expr.node {
243             ast::ExprParen(subexpr) => {
244                 self.walk_expr(subexpr)
245             }
246
247             ast::ExprPath(..) => { }
248
249             ast::ExprUnary(ast::UnDeref, base) => {      // *base
250                 if !self.walk_overloaded_operator(expr, base, []) {
251                     self.select_from_expr(base);
252                 }
253             }
254
255             ast::ExprField(base, _, _) => {         // base.f
256                 self.select_from_expr(base);
257             }
258
259             ast::ExprIndex(lhs, rhs) => {           // lhs[rhs]
260                 if !self.walk_overloaded_operator(expr, lhs, [rhs]) {
261                     self.select_from_expr(lhs);
262                     self.consume_expr(rhs);
263                 }
264             }
265
266             ast::ExprCall(callee, ref args) => {    // callee(args)
267                 self.walk_callee(expr, callee);
268                 self.consume_exprs(args);
269             }
270
271             ast::ExprMethodCall(_, _, ref args) => { // callee.m(args)
272                 self.consume_exprs(args);
273             }
274
275             ast::ExprStruct(_, ref fields, opt_with) => {
276                 self.walk_struct_expr(expr, fields, opt_with);
277             }
278
279             ast::ExprTup(ref exprs) => {
280                 self.consume_exprs(exprs);
281             }
282
283             ast::ExprIf(cond_expr, then_blk, opt_else_expr) => {
284                 self.consume_expr(cond_expr);
285                 self.walk_block(then_blk);
286                 for else_expr in opt_else_expr.iter() {
287                     self.consume_expr(*else_expr);
288                 }
289             }
290
291             ast::ExprMatch(discr, ref arms) => {
292                 // treatment of the discriminant is handled while
293                 // walking the arms:
294                 self.walk_expr(discr);
295                 let discr_cmt = return_if_err!(self.mc.cat_expr(discr));
296                 for arm in arms.iter() {
297                     self.walk_arm(discr_cmt.clone(), arm);
298                 }
299             }
300
301             ast::ExprVec(ref exprs) => {
302                 self.consume_exprs(exprs);
303             }
304
305             ast::ExprAddrOf(m, base) => {   // &base
306                 // make sure that the thing we are pointing out stays valid
307                 // for the lifetime `scope_r` of the resulting ptr:
308                 let expr_ty = ty::expr_ty(self.tcx(), expr);
309                 if !ty::type_is_bot(expr_ty) {
310                     let r = ty::ty_region(self.tcx(), expr.span, expr_ty);
311                     let bk = ty::BorrowKind::from_mutbl(m);
312                     self.borrow_expr(base, r, bk, AddrOf);
313                 } else {
314                     self.walk_expr(base);
315                 }
316             }
317
318             ast::ExprInlineAsm(ref ia) => {
319                 for &(_, input) in ia.inputs.iter() {
320                     self.consume_expr(input);
321                 }
322
323                 for &(_, output) in ia.outputs.iter() {
324                     self.mutate_expr(expr, output, JustWrite);
325                 }
326             }
327
328             ast::ExprBreak(..) |
329             ast::ExprAgain(..) |
330             ast::ExprLit(..) => {}
331
332             ast::ExprLoop(blk, _) => {
333                 self.walk_block(blk);
334             }
335
336             ast::ExprWhile(cond_expr, blk) => {
337                 self.consume_expr(cond_expr);
338                 self.walk_block(blk);
339             }
340
341             ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop"),
342
343             ast::ExprUnary(_, lhs) => {
344                 if !self.walk_overloaded_operator(expr, lhs, []) {
345                     self.consume_expr(lhs);
346                 }
347             }
348
349             ast::ExprBinary(_, lhs, rhs) => {
350                 if !self.walk_overloaded_operator(expr, lhs, [rhs]) {
351                     self.consume_expr(lhs);
352                     self.consume_expr(rhs);
353                 }
354             }
355
356             ast::ExprBlock(blk) => {
357                 self.walk_block(blk);
358             }
359
360             ast::ExprRet(ref opt_expr) => {
361                 for expr in opt_expr.iter() {
362                     self.consume_expr(*expr);
363                 }
364             }
365
366             ast::ExprAssign(lhs, rhs) => {
367                 self.mutate_expr(expr, lhs, JustWrite);
368                 self.consume_expr(rhs);
369             }
370
371             ast::ExprCast(base, _) => {
372                 self.consume_expr(base);
373             }
374
375             ast::ExprAssignOp(_, lhs, rhs) => {
376                 // This will have to change if/when we support
377                 // overloaded operators for `+=` and so forth.
378                 self.mutate_expr(expr, lhs, WriteAndRead);
379                 self.consume_expr(rhs);
380             }
381
382             ast::ExprRepeat(base, count) => {
383                 self.consume_expr(base);
384                 self.consume_expr(count);
385             }
386
387             ast::ExprFnBlock(..) |
388             ast::ExprProc(..) => {
389                 self.walk_captures(expr)
390             }
391
392             ast::ExprVstore(base, _) => {
393                 self.consume_expr(base);
394             }
395
396             ast::ExprBox(place, base) => {
397                 self.consume_expr(place);
398                 self.consume_expr(base);
399             }
400
401             ast::ExprMac(..) => {
402                 self.tcx().sess.span_bug(
403                     expr.span,
404                     "macro expression remains after expansion");
405             }
406         }
407     }
408
409     fn walk_callee(&mut self, call: &ast::Expr, callee: &ast::Expr) {
410         let callee_ty = ty::expr_ty_adjusted(self.tcx(), callee);
411         debug!("walk_callee: callee={} callee_ty={}",
412                callee.repr(self.tcx()), callee_ty.repr(self.tcx()));
413         match ty::get(callee_ty).sty {
414             ty::ty_bare_fn(..) => {
415                 self.consume_expr(callee);
416             }
417             ty::ty_closure(ref f) => {
418                 match f.onceness {
419                     ast::Many => {
420                         self.borrow_expr(callee,
421                                          ty::ReScope(call.id),
422                                          ty::UniqueImmBorrow,
423                                          ClosureInvocation);
424                     }
425                     ast::Once => {
426                         self.consume_expr(callee);
427                     }
428                 }
429             }
430             _ => {
431                 match self.tcx()
432                           .method_map
433                           .borrow()
434                           .find(&MethodCall::expr(call.id)) {
435                     Some(_) => {
436                         // FIXME(#14774, pcwalton): Implement this.
437                     }
438                     None => {
439                         self.tcx().sess.span_bug(
440                             callee.span,
441                             format!("unxpected callee type {}",
442                                     callee_ty.repr(self.tcx())).as_slice());
443                     }
444                 }
445             }
446         }
447     }
448
449     fn walk_stmt(&mut self, stmt: &ast::Stmt) {
450         match stmt.node {
451             ast::StmtDecl(decl, _) => {
452                 match decl.node {
453                     ast::DeclLocal(local) => {
454                         self.walk_local(local);
455                     }
456
457                     ast::DeclItem(_) => {
458                         // we don't visit nested items in this visitor,
459                         // only the fn body we were given.
460                     }
461                 }
462             }
463
464             ast::StmtExpr(expr, _) |
465             ast::StmtSemi(expr, _) => {
466                 self.consume_expr(expr);
467             }
468
469             ast::StmtMac(..) => {
470                 self.tcx().sess.span_bug(stmt.span, "unexpanded stmt macro");
471             }
472         }
473     }
474
475     fn walk_local(&mut self, local: @ast::Local) {
476         match local.init {
477             None => {
478                 let delegate = &mut self.delegate;
479                 pat_util::pat_bindings(&self.typer.tcx().def_map, local.pat, |_, id, span, _| {
480                     delegate.decl_without_init(id, span);
481                 })
482             }
483
484             Some(expr) => {
485                 // Variable declarations with
486                 // initializers are considered
487                 // "assigns", which is handled by
488                 // `walk_pat`:
489                 self.walk_expr(expr);
490                 let init_cmt = return_if_err!(self.mc.cat_expr(expr));
491                 self.walk_pat(init_cmt, local.pat);
492             }
493         }
494     }
495
496     fn walk_block(&mut self, blk: &ast::Block) {
497         /*!
498          * Indicates that the value of `blk` will be consumed,
499          * meaning either copied or moved depending on its type.
500          */
501
502         debug!("walk_block(blk.id={:?})", blk.id);
503
504         for stmt in blk.stmts.iter() {
505             self.walk_stmt(*stmt);
506         }
507
508         for tail_expr in blk.expr.iter() {
509             self.consume_expr(*tail_expr);
510         }
511     }
512
513     fn walk_struct_expr(&mut self,
514                         _expr: &ast::Expr,
515                         fields: &Vec<ast::Field>,
516                         opt_with: Option<@ast::Expr>) {
517         // Consume the expressions supplying values for each field.
518         for field in fields.iter() {
519             self.consume_expr(field.expr);
520         }
521
522         let with_expr = match opt_with {
523             Some(w) => { w }
524             None => { return; }
525         };
526
527         let with_cmt = return_if_err!(self.mc.cat_expr(with_expr));
528
529         // Select just those fields of the `with`
530         // expression that will actually be used
531         let with_fields = match ty::get(with_cmt.ty).sty {
532             ty::ty_struct(did, ref substs) => {
533                 ty::struct_fields(self.tcx(), did, substs)
534             }
535             _ => {
536                 self.tcx().sess.span_bug(
537                     with_expr.span,
538                     "with expression doesn't evaluate to a struct");
539             }
540         };
541
542         // Consume those fields of the with expression that are needed.
543         for with_field in with_fields.iter() {
544             if !contains_field_named(with_field, fields) {
545                 let cmt_field = self.mc.cat_field(with_expr,
546                                                   with_cmt.clone(),
547                                                   with_field.ident,
548                                                   with_field.mt.ty);
549                 self.delegate_consume(with_expr.id, with_expr.span, cmt_field);
550             }
551         }
552
553         fn contains_field_named(field: &ty::field,
554                                 fields: &Vec<ast::Field>)
555                                 -> bool
556         {
557             fields.iter().any(
558                 |f| f.ident.node.name == field.ident.name)
559         }
560     }
561
562     // Invoke the appropriate delegate calls for anything that gets
563     // consumed or borrowed as part of the automatic adjustment
564     // process.
565     fn walk_adjustment(&mut self, expr: &ast::Expr) {
566         let typer = self.typer;
567         match typer.adjustments().borrow().find(&expr.id) {
568             None => { }
569             Some(adjustment) => {
570                 match *adjustment {
571                     ty::AutoAddEnv(..) |
572                     ty::AutoObject(..) => {
573                         // Creating an object or closure consumes the
574                         // input and stores it into the resulting rvalue.
575                         debug!("walk_adjustment(AutoAddEnv|AutoObject)");
576                         let cmt_unadjusted =
577                             return_if_err!(self.mc.cat_expr_unadjusted(expr));
578                         self.delegate_consume(expr.id, expr.span, cmt_unadjusted);
579                     }
580                     ty::AutoDerefRef(ty::AutoDerefRef {
581                         autoref: ref opt_autoref,
582                         autoderefs: n
583                     }) => {
584                         self.walk_autoderefs(expr, n);
585
586                         match *opt_autoref {
587                             None => { }
588                             Some(ref r) => {
589                                 self.walk_autoref(expr, r, n);
590                             }
591                         }
592                     }
593                 }
594             }
595         }
596     }
597
598     fn walk_autoderefs(&mut self,
599                        expr: &ast::Expr,
600                        autoderefs: uint) {
601         /*!
602          * Autoderefs for overloaded Deref calls in fact reference
603          * their receiver. That is, if we have `(*x)` where `x` is of
604          * type `Rc<T>`, then this in fact is equivalent to
605          * `x.deref()`. Since `deref()` is declared with `&self`, this
606          * is an autoref of `x`.
607          */
608         debug!("walk_autoderefs expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
609
610         for i in range(0, autoderefs) {
611             let deref_id = typeck::MethodCall::autoderef(expr.id, i as u32);
612             match self.typer.node_method_ty(deref_id) {
613                 None => {}
614                 Some(method_ty) => {
615                     let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i));
616                     let self_ty = *ty::ty_fn_args(method_ty).get(0);
617                     let (m, r) = match ty::get(self_ty).sty {
618                         ty::ty_rptr(r, ref m) => (m.mutbl, r),
619                         _ => self.tcx().sess.span_bug(expr.span,
620                                 format!("bad overloaded deref type {}",
621                                     method_ty.repr(self.tcx())).as_slice())
622                     };
623                     let bk = ty::BorrowKind::from_mutbl(m);
624                     self.delegate.borrow(expr.id, expr.span, cmt,
625                                          r, bk, AutoRef);
626                 }
627             }
628         }
629     }
630
631     fn walk_autoref(&mut self,
632                     expr: &ast::Expr,
633                     autoref: &ty::AutoRef,
634                     autoderefs: uint) {
635         debug!("walk_autoref expr={} autoderefs={}", expr.repr(self.tcx()), autoderefs);
636
637         let cmt_derefd = return_if_err!(
638             self.mc.cat_expr_autoderefd(expr, autoderefs));
639
640         debug!("walk_autoref: cmt_derefd={}", cmt_derefd.repr(self.tcx()));
641
642         match *autoref {
643             ty::AutoPtr(r, m) => {
644                 self.delegate.borrow(expr.id,
645                                      expr.span,
646                                      cmt_derefd,
647                                      r,
648                                      ty::BorrowKind::from_mutbl(m),
649                                      AutoRef)
650             }
651             ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
652                 let cmt_index = self.mc.cat_index(expr, cmt_derefd, autoderefs+1);
653                 self.delegate.borrow(expr.id,
654                                      expr.span,
655                                      cmt_index,
656                                      r,
657                                      ty::BorrowKind::from_mutbl(m),
658                                      AutoRef)
659             }
660             ty::AutoBorrowObj(r, m) => {
661                 let cmt_deref = self.mc.cat_deref_obj(expr, cmt_derefd);
662                 self.delegate.borrow(expr.id,
663                                      expr.span,
664                                      cmt_deref,
665                                      r,
666                                      ty::BorrowKind::from_mutbl(m),
667                                      AutoRef)
668             }
669             ty::AutoUnsafe(_) => {}
670         }
671     }
672
673     fn walk_overloaded_operator(&mut self,
674                                 expr: &ast::Expr,
675                                 receiver: &ast::Expr,
676                                 args: &[@ast::Expr])
677                                 -> bool
678     {
679         if !self.typer.is_method_call(expr.id) {
680             return false;
681         }
682
683         self.walk_expr(receiver);
684
685         // Arguments (but not receivers) to overloaded operator
686         // methods are implicitly autoref'd which sadly does not use
687         // adjustments, so we must hardcode the borrow here.
688
689         let r = ty::ReScope(expr.id);
690         let bk = ty::ImmBorrow;
691
692         for &arg in args.iter() {
693             self.borrow_expr(arg, r, bk, OverloadedOperator);
694         }
695         return true;
696     }
697
698     fn walk_arm(&mut self, discr_cmt: mc::cmt, arm: &ast::Arm) {
699         for &pat in arm.pats.iter() {
700             self.walk_pat(discr_cmt.clone(), pat);
701         }
702
703         for guard in arm.guard.iter() {
704             self.consume_expr(*guard);
705         }
706
707         self.consume_expr(arm.body);
708     }
709
710     fn walk_pat(&mut self, cmt_discr: mc::cmt, pat: @ast::Pat) {
711         debug!("walk_pat cmt_discr={} pat={}", cmt_discr.repr(self.tcx()),
712                pat.repr(self.tcx()));
713         let mc = &self.mc;
714         let typer = self.typer;
715         let tcx = typer.tcx();
716         let def_map = &self.typer.tcx().def_map;
717         let delegate = &mut self.delegate;
718         return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| {
719             if pat_util::pat_is_binding(def_map, pat) {
720                 let tcx = typer.tcx();
721
722                 debug!("binding cmt_pat={} pat={}",
723                        cmt_pat.repr(tcx),
724                        pat.repr(tcx));
725
726                 // pat_ty: the type of the binding being produced.
727                 let pat_ty = ty::node_id_to_type(tcx, pat.id);
728
729                 // Each match binding is effectively an assignment to the
730                 // binding being produced.
731                 let def = def_map.borrow().get_copy(&pat.id);
732                 match mc.cat_def(pat.id, pat.span, pat_ty, def) {
733                     Ok(binding_cmt) => {
734                         delegate.mutate(pat.id, pat.span, binding_cmt, Init);
735                     }
736                     Err(_) => { }
737                 }
738
739                 // It is also a borrow or copy/move of the value being matched.
740                 match pat.node {
741                     ast::PatIdent(ast::BindByRef(m), _, _) => {
742                         let (r, bk) = {
743                             (ty::ty_region(tcx, pat.span, pat_ty),
744                              ty::BorrowKind::from_mutbl(m))
745                         };
746                         delegate.borrow(pat.id, pat.span, cmt_pat,
747                                              r, bk, RefBinding);
748                     }
749                     ast::PatIdent(ast::BindByValue(_), _, _) => {
750                         let mode = copy_or_move(typer.tcx(), cmt_pat.ty, PatBindingMove);
751                         delegate.consume_pat(pat, cmt_pat, mode);
752                     }
753                     _ => {
754                         typer.tcx().sess.span_bug(
755                             pat.span,
756                             "binding pattern not an identifier");
757                     }
758                 }
759             } else {
760                 match pat.node {
761                     ast::PatVec(_, Some(slice_pat), _) => {
762                         // The `slice_pat` here creates a slice into
763                         // the original vector.  This is effectively a
764                         // borrow of the elements of the vector being
765                         // matched.
766
767                         let (slice_cmt, slice_mutbl, slice_r) = {
768                             match mc.cat_slice_pattern(cmt_pat, slice_pat) {
769                                 Ok(v) => v,
770                                 Err(()) => {
771                                     tcx.sess.span_bug(slice_pat.span,
772                                                       "Err from mc")
773                                 }
774                             }
775                         };
776
777                         // Note: We declare here that the borrow
778                         // occurs upon entering the `[...]`
779                         // pattern. This implies that something like
780                         // `[a, ..b]` where `a` is a move is illegal,
781                         // because the borrow is already in effect.
782                         // In fact such a move would be safe-ish, but
783                         // it effectively *requires* that we use the
784                         // nulling out semantics to indicate when a
785                         // value has been moved, which we are trying
786                         // to move away from.  Otherwise, how can we
787                         // indicate that the first element in the
788                         // vector has been moved?  Eventually, we
789                         // could perhaps modify this rule to permit
790                         // `[..a, b]` where `b` is a move, because in
791                         // that case we can adjust the length of the
792                         // original vec accordingly, but we'd have to
793                         // make trans do the right thing, and it would
794                         // only work for `~` vectors. It seems simpler
795                         // to just require that people call
796                         // `vec.pop()` or `vec.unshift()`.
797                         let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl);
798                         delegate.borrow(pat.id, pat.span,
799                                         slice_cmt, slice_r,
800                                         slice_bk, RefBinding);
801                     }
802                     _ => { }
803                 }
804             }
805         }));
806     }
807
808     fn walk_captures(&mut self, closure_expr: &ast::Expr) {
809         debug!("walk_captures({})", closure_expr.repr(self.tcx()));
810
811         let tcx = self.typer.tcx();
812         freevars::with_freevars(tcx, closure_expr.id, |freevars| {
813             match freevars::get_capture_mode(self.tcx(), closure_expr.id) {
814                 freevars::CaptureByRef => {
815                     self.walk_by_ref_captures(closure_expr, freevars);
816                 }
817                 freevars::CaptureByValue => {
818                     self.walk_by_value_captures(closure_expr, freevars);
819                 }
820             }
821         });
822     }
823
824     fn walk_by_ref_captures(&mut self,
825                             closure_expr: &ast::Expr,
826                             freevars: &[freevars::freevar_entry]) {
827         for freevar in freevars.iter() {
828             let id_var = freevar.def.def_id().node;
829             let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
830                                                                closure_expr.span,
831                                                                freevar.def));
832
833             // Lookup the kind of borrow the callee requires, as
834             // inferred by regionbk
835             let upvar_id = ty::UpvarId { var_id: id_var,
836                                          closure_expr_id: closure_expr.id };
837             let upvar_borrow = self.tcx().upvar_borrow_map.borrow()
838                                    .get_copy(&upvar_id);
839
840             self.delegate.borrow(closure_expr.id,
841                                  closure_expr.span,
842                                  cmt_var,
843                                  upvar_borrow.region,
844                                  upvar_borrow.kind,
845                                  ClosureCapture(freevar.span));
846         }
847     }
848
849     fn walk_by_value_captures(&mut self,
850                               closure_expr: &ast::Expr,
851                               freevars: &[freevars::freevar_entry]) {
852         for freevar in freevars.iter() {
853             let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id,
854                                                                closure_expr.span,
855                                                                freevar.def));
856             let mode = copy_or_move(self.tcx(), cmt_var.ty, CaptureMove);
857             self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode);
858         }
859     }
860
861     fn cat_captured_var(&mut self,
862                         closure_id: ast::NodeId,
863                         closure_span: Span,
864                         upvar_def: def::Def)
865                         -> mc::McResult<mc::cmt> {
866         // Create the cmt for the variable being borrowed, from the
867         // caller's perspective
868         let var_id = upvar_def.def_id().node;
869         let var_ty = ty::node_id_to_type(self.tcx(), var_id);
870         self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def)
871     }
872 }
873
874 fn copy_or_move(tcx: &ty::ctxt, ty: ty::t, move_reason: MoveReason) -> ConsumeMode {
875     if ty::type_moves_by_default(tcx, ty) { Move(move_reason) } else { Copy }
876 }
877