]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/moves.rs
libsyntax/librustc: Allow mut qualifier in patterns.
[rust.git] / src / librustc / middle / moves.rs
1 // Copyright 2012 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
13 # Moves Computation
14
15 The goal of this file is to compute which
16 expressions/patterns/captures correspond to *moves*.  This is
17 generally a function of the context in which the expression appears as
18 well as the expression's type.
19
20 ## Examples
21
22 We will use the following fragment of code to explain the various
23 considerations.  Note that in this code `x` is used after it has been
24 moved here.  This is not relevant to this pass, though the information
25 we compute would later be used to detect this error (see the section
26 Enforcement of Moves, below).
27
28     struct Foo { a: int, b: ~int }
29     let x: Foo = ...;
30     let w = (x {Read}).a;      // Read
31     let y = (x {Move}).b;      // Move
32     let z = copy (x {Read}).b; // Read
33
34 Let's look at these examples one by one.  In the first case, `w`, the
35 expression being assigned is `x.a`, which has `int` type.  In that
36 case, the value is read, and the container (`x`) is also read.
37
38 In the second case, `y`, `x.b` is being assigned which has type
39 `~int`.  Because this type moves by default, that will be a move
40 reference.  Whenever we move from a compound expression like `x.b` (or
41 `x[b]` or `*x` or `{x)[b].c`, etc), this invalidates all containing
42 expressions since we do not currently permit "incomplete" variables
43 where part of them has been moved and part has not.  In this case,
44 this means that the reference to `x` is also a move.  We'll see later,
45 though, that these kind of "partial moves", where part of the
46 expression has been moved, are classified and stored somewhat
47 differently.
48
49 The final example (`z`) is `copy x.b`: in this case, although the
50 expression being assigned has type `~int`, there are no moves
51 involved.
52
53 ### Patterns
54
55 For each binding in a match or let pattern, we also compute a read
56 or move designation.  A move binding means that the value will be
57 moved from the value being matched.  As a result, the expression
58 being matched (aka, the 'discriminant') is either moved or read
59 depending on whethe the bindings move the value they bind to out of
60 the discriminant.
61
62 For examples, consider this match expression:
63
64     match x {Move} {
65       Foo { a: a {Read}, b: b {Move} } => {...}
66     }
67
68 Here, the binding `b` is value (not ref) mode, and `b` has type
69 `~int`, and therefore the discriminant expression `x` would be
70 incomplete so it also considered moved.
71
72 In the following two examples, in contrast, the mode of `b` is either
73 `copy` or `ref` and hence the overall result is a read:
74
75     match x {Read} {
76       Foo { a: a {Read}, b: copy b {Read} } => {...}
77     }
78
79     match x {Read} {
80       Foo { a: a {Read}, b: ref b {Read} } => {...}
81     }
82
83 Similar reasoning can be applied to `let` expressions:
84
85     let Foo { a: a {Read}, b: b {Move} } = x {Move};
86     let Foo { a: a {Read}, b: copy b {Read} } = x {Read};
87     let Foo { a: a {Read}, b: ref b  {Read} } = x {Read};
88
89 ## Output
90
91 The pass results in the struct `MoveMaps` which contains several
92 maps:
93
94 `moves_map` is a set containing the id of every *outermost expression* or
95 *binding* that causes a move.  Note that `moves_map` only contains the *outermost
96 expressions* that are moved.  Therefore, if you have a use of `x.b`,
97 as in the example `y` above, the expression `x.b` would be in the
98 `moves_map` but not `x`.  The reason for this is that, for most
99 purposes, it's only the outermost expression that is needed.  The
100 borrow checker and trans, for example, only care about the outermost
101 expressions that are moved.  It is more efficient therefore just to
102 store those entries.
103
104 Sometimes though we want to know the variables that are moved (in
105 particular in the borrow checker). For these cases, the set
106 `moved_variables_set` just collects the ids of variables that are
107 moved.
108
109 Finally, the `capture_map` maps from the node_id of a closure
110 expression to an array of `CaptureVar` structs detailing which
111 variables are captured and how (by ref, by copy, by move).
112
113 ## Enforcement of Moves
114
115 The enforcement of moves is done by the borrow checker.  Please see
116 the section "Moves and initialization" in `middle/borrowck/doc.rs`.
117
118 ## Distributive property
119
120 Copies are "distributive" over parenthesization, but blocks are
121 considered rvalues.  What this means is that, for example, neither
122 `a.clone()` nor `(a).clone()` will move `a` (presuming that `a` has a
123 linear type and `clone()` takes its self by reference), but
124 `{a}.clone()` will move `a`, as would `(if cond {a} else {b}).clone()`
125 and so on.
126
127 */
128
129
130 use middle::pat_util::{pat_bindings};
131 use middle::freevars;
132 use middle::ty;
133 use middle::typeck::{method_map};
134 use util::ppaux;
135 use util::ppaux::Repr;
136 use util::common::indenter;
137 use util::ppaux::UserString;
138
139 use std::at_vec;
140 use std::hashmap::{HashSet, HashMap};
141 use syntax::ast::*;
142 use syntax::ast_util;
143 use syntax::visit;
144 use syntax::visit::Visitor;
145 use syntax::codemap::Span;
146
147 #[deriving(Eq, Encodable, Decodable)]
148 pub enum CaptureMode {
149     CapCopy, // Copy the value into the closure.
150     CapMove, // Move the value into the closure.
151     CapRef,  // Reference directly from parent stack frame (used by `&fn()`).
152 }
153
154 #[deriving(Encodable, Decodable)]
155 pub struct CaptureVar {
156     def: Def,         // Variable being accessed free
157     span: Span,       // Location of an access to this variable
158     mode: CaptureMode // How variable is being accessed
159 }
160
161 pub type CaptureMap = @mut HashMap<NodeId, @[CaptureVar]>;
162
163 pub type MovesMap = @mut HashSet<NodeId>;
164
165 /**
166  * Set of variable node-ids that are moved.
167  *
168  * Note: The `VariableMovesMap` stores expression ids that
169  * are moves, whereas this set stores the ids of the variables
170  * that are moved at some point */
171 pub type MovedVariablesSet = @mut HashSet<NodeId>;
172
173 /** See the section Output on the module comment for explanation. */
174 #[deriving(Clone)]
175 pub struct MoveMaps {
176     moves_map: MovesMap,
177     moved_variables_set: MovedVariablesSet,
178     capture_map: CaptureMap
179 }
180
181 #[deriving(Clone)]
182 struct VisitContext {
183     tcx: ty::ctxt,
184     method_map: method_map,
185     move_maps: MoveMaps
186 }
187
188 #[deriving(Eq)]
189 enum UseMode {
190     Move,        // This value or something owned by it is moved.
191     Read         // Read no matter what the type.
192 }
193
194 impl visit::Visitor<()> for VisitContext {
195     fn visit_fn(&mut self, fk:&visit::fn_kind, fd:&fn_decl,
196                 b:&Block, s:Span, n:NodeId, _:()) {
197         compute_modes_for_fn(self, fk, fd, b, s, n);
198     }
199     fn visit_expr(&mut self, ex:@Expr, _:()) {
200         compute_modes_for_expr(self, ex);
201     }
202     fn visit_local(&mut self, l:@Local, _:()) {
203         compute_modes_for_local(self, l);
204     }
205 }
206
207 pub fn compute_moves(tcx: ty::ctxt,
208                      method_map: method_map,
209                      crate: &Crate) -> MoveMaps
210 {
211     let mut visit_cx = VisitContext {
212         tcx: tcx,
213         method_map: method_map,
214         move_maps: MoveMaps {
215             moves_map: @mut HashSet::new(),
216             capture_map: @mut HashMap::new(),
217             moved_variables_set: @mut HashSet::new()
218         }
219     };
220     let visit_cx = &mut visit_cx;
221     visit::walk_crate(visit_cx, crate, ());
222     return visit_cx.move_maps;
223 }
224
225 pub fn moved_variable_node_id_from_def(def: Def) -> Option<NodeId> {
226     match def {
227       DefBinding(nid, _) |
228       DefArg(nid, _) |
229       DefLocal(nid, _) |
230       DefSelf(nid, _) => Some(nid),
231
232       _ => None
233     }
234 }
235
236 ///////////////////////////////////////////////////////////////////////////
237 // Expressions
238
239 fn compute_modes_for_local<'a>(cx: &mut VisitContext,
240                                local: @Local) {
241     cx.use_pat(local.pat);
242     for &init in local.init.iter() {
243         cx.use_expr(init, Read);
244     }
245 }
246
247 fn compute_modes_for_fn(cx: &mut VisitContext,
248                         fk: &visit::fn_kind,
249                         decl: &fn_decl,
250                         body: &Block,
251                         span: Span,
252                         id: NodeId) {
253     for a in decl.inputs.iter() {
254         cx.use_pat(a.pat);
255     }
256     visit::walk_fn(cx, fk, decl, body, span, id, ());
257 }
258
259 fn compute_modes_for_expr(cx: &mut VisitContext,
260                           expr: @Expr)
261 {
262     cx.consume_expr(expr);
263 }
264
265 impl VisitContext {
266     pub fn consume_exprs(&mut self, exprs: &[@Expr]) {
267         for expr in exprs.iter() {
268             self.consume_expr(*expr);
269         }
270     }
271
272     pub fn consume_expr(&mut self, expr: @Expr) {
273         /*!
274          * Indicates that the value of `expr` will be consumed,
275          * meaning either copied or moved depending on its type.
276          */
277
278         debug!("consume_expr(expr={})",
279                expr.repr(self.tcx));
280
281         let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
282         if ty::type_moves_by_default(self.tcx, expr_ty) {
283             self.move_maps.moves_map.insert(expr.id);
284             self.use_expr(expr, Move);
285         } else {
286             self.use_expr(expr, Read);
287         };
288     }
289
290     pub fn consume_block(&mut self, blk: &Block) {
291         /*!
292          * Indicates that the value of `blk` will be consumed,
293          * meaning either copied or moved depending on its type.
294          */
295
296         debug!("consume_block(blk.id={:?})", blk.id);
297
298         for stmt in blk.stmts.iter() {
299             self.visit_stmt(*stmt, ());
300         }
301
302         for tail_expr in blk.expr.iter() {
303             self.consume_expr(*tail_expr);
304         }
305     }
306
307     pub fn use_expr(&mut self,
308                     expr: @Expr,
309                     expr_mode: UseMode) {
310         /*!
311          * Indicates that `expr` is used with a given mode.  This will
312          * in turn trigger calls to the subcomponents of `expr`.
313          */
314
315         debug!("use_expr(expr={}, mode={:?})",
316                expr.repr(self.tcx),
317                expr_mode);
318
319         // `expr_mode` refers to the post-adjustment value.  If one of
320         // those adjustments is to take a reference, then it's only
321         // reading the underlying expression, not moving it.
322         let comp_mode = match self.tcx.adjustments.find(&expr.id) {
323             Some(&@ty::AutoDerefRef(
324                 ty::AutoDerefRef {
325                     autoref: Some(_), _})) => Read,
326             _ => expr_mode
327         };
328
329         debug!("comp_mode = {:?}", comp_mode);
330
331         match expr.node {
332             ExprPath(*) | ExprSelf => {
333                 match comp_mode {
334                     Move => {
335                         let def = self.tcx.def_map.get_copy(&expr.id);
336                         let r = moved_variable_node_id_from_def(def);
337                         for &id in r.iter() {
338                             self.move_maps.moved_variables_set.insert(id);
339                         }
340                     }
341                     Read => {}
342                 }
343             }
344
345             ExprUnary(_, UnDeref, base) => {       // *base
346                 if !self.use_overloaded_operator(expr, base, [])
347                 {
348                     // Moving out of *base moves out of base.
349                     self.use_expr(base, comp_mode);
350                 }
351             }
352
353             ExprField(base, _, _) => {        // base.f
354                 // Moving out of base.f moves out of base.
355                 self.use_expr(base, comp_mode);
356             }
357
358             ExprIndex(_, lhs, rhs) => {          // lhs[rhs]
359                 if !self.use_overloaded_operator(expr, lhs, [rhs])
360                 {
361                     self.use_expr(lhs, comp_mode);
362                     self.consume_expr(rhs);
363                 }
364             }
365
366             ExprCall(callee, ref args, _) => {    // callee(args)
367                 // Figure out whether the called function is consumed.
368                 let mode = match ty::get(ty::expr_ty(self.tcx, callee)).sty {
369                     ty::ty_closure(ref cty) => {
370                         match cty.onceness {
371                         Once => Move,
372                         Many => Read,
373                         }
374                     },
375                     ty::ty_bare_fn(*) => Read,
376                     ref x =>
377                         self.tcx.sess.span_bug(callee.span,
378                             format!("non-function type in moves for expr_call: {:?}", x)),
379                 };
380                 // Note we're not using consume_expr, which uses type_moves_by_default
381                 // to determine the mode, for this. The reason is that while stack
382                 // closures should be noncopyable, they shouldn't move by default;
383                 // calling a closure should only consume it if it's once.
384                 if mode == Move {
385                     self.move_maps.moves_map.insert(callee.id);
386                 }
387                 self.use_expr(callee, mode);
388                 self.use_fn_args(callee.id, *args);
389             }
390
391             ExprMethodCall(callee_id, rcvr, _, _, ref args, _) => { // callee.m(args)
392                 // Implicit self is equivalent to & mode, but every
393                 // other kind should be + mode.
394                 self.use_receiver(rcvr);
395                 self.use_fn_args(callee_id, *args);
396             }
397
398             ExprStruct(_, ref fields, opt_with) => {
399                 for field in fields.iter() {
400                     self.consume_expr(field.expr);
401                 }
402
403                 for with_expr in opt_with.iter() {
404                     // If there are any fields whose type is move-by-default,
405                     // then `with` is consumed, otherwise it is only read
406                     let with_ty = ty::expr_ty(self.tcx, *with_expr);
407                     let with_fields = match ty::get(with_ty).sty {
408                         ty::ty_struct(did, ref substs) => {
409                             ty::struct_fields(self.tcx, did, substs)
410                         }
411                         ref r => {
412                            self.tcx.sess.span_bug(
413                                 with_expr.span,
414                                 format!("bad base expr type in record: {:?}", r))
415                         }
416                     };
417
418                     // The `with` expr must be consumed if it contains
419                     // any fields which (1) were not explicitly
420                     // specified and (2) have a type that
421                     // moves-by-default:
422                     let consume_with = with_fields.iter().any(|tf| {
423                         !fields.iter().any(|f| f.ident.name == tf.ident.name) &&
424                             ty::type_moves_by_default(self.tcx, tf.mt.ty)
425                     });
426
427                     fn has_dtor(tcx: ty::ctxt, ty: ty::t) -> bool {
428                         use middle::ty::{get,ty_struct,ty_enum};
429                         match get(ty).sty {
430                             ty_struct(did, _) | ty_enum(did, _) => ty::has_dtor(tcx, did),
431                             _ => false,
432                         }
433                     }
434
435                     if consume_with {
436                         if has_dtor(self.tcx, with_ty) {
437                             self.tcx.sess.span_err(with_expr.span,
438                                                    format!("cannot move out of type `{}`, \
439                                                          which defines the `Drop` trait",
440                                                         with_ty.user_string(self.tcx)));
441                         }
442                         self.consume_expr(*with_expr);
443                     } else {
444                         self.use_expr(*with_expr, Read);
445                     }
446                 }
447             }
448
449             ExprTup(ref exprs) => {
450                 self.consume_exprs(*exprs);
451             }
452
453             ExprIf(cond_expr, ref then_blk, opt_else_expr) => {
454                 self.consume_expr(cond_expr);
455                 self.consume_block(then_blk);
456                 for else_expr in opt_else_expr.iter() {
457                     self.consume_expr(*else_expr);
458                 }
459             }
460
461             ExprMatch(discr, ref arms) => {
462                 // We must do this first so that `arms_have_by_move_bindings`
463                 // below knows which bindings are moves.
464                 for arm in arms.iter() {
465                     self.consume_arm(arm);
466                 }
467
468                 // The discriminant may, in fact, be partially moved
469                 // if there are by-move bindings, but borrowck deals
470                 // with that itself.
471                 self.use_expr(discr, Read);
472             }
473
474             ExprParen(base) => {
475                 // Note: base is not considered a *component* here, so
476                 // use `expr_mode` not `comp_mode`.
477                 self.use_expr(base, expr_mode);
478             }
479
480             ExprVec(ref exprs, _) => {
481                 self.consume_exprs(*exprs);
482             }
483
484             ExprAddrOf(_, base) => {   // &base
485                 self.use_expr(base, Read);
486             }
487
488             ExprLogLevel |
489             ExprInlineAsm(*) |
490             ExprBreak(*) |
491             ExprAgain(*) |
492             ExprLit(*) => {}
493
494             ExprLoop(ref blk, _) => {
495                 self.consume_block(blk);
496             }
497
498             ExprWhile(cond_expr, ref blk) => {
499                 self.consume_expr(cond_expr);
500                 self.consume_block(blk);
501             }
502
503             ExprForLoop(*) => fail!("non-desugared expr_for_loop"),
504
505             ExprUnary(_, _, lhs) => {
506                 if !self.use_overloaded_operator(expr, lhs, [])
507                 {
508                     self.consume_expr(lhs);
509                 }
510             }
511
512             ExprBinary(_, _, lhs, rhs) => {
513                 if !self.use_overloaded_operator(expr, lhs, [rhs])
514                 {
515                     self.consume_expr(lhs);
516                     self.consume_expr(rhs);
517                 }
518             }
519
520             ExprBlock(ref blk) => {
521                 self.consume_block(blk);
522             }
523
524             ExprRet(ref opt_expr) => {
525                 for expr in opt_expr.iter() {
526                     self.consume_expr(*expr);
527                 }
528             }
529
530             ExprAssign(lhs, rhs) => {
531                 self.use_expr(lhs, Read);
532                 self.consume_expr(rhs);
533             }
534
535             ExprCast(base, _) => {
536                 self.consume_expr(base);
537             }
538
539             ExprAssignOp(_, _, lhs, rhs) => {
540                 // FIXME(#4712) --- Overloaded operators?
541                 //
542                 // if !self.use_overloaded_operator(expr, DoDerefArgs, lhs, [rhs])
543                 // {
544                 self.consume_expr(lhs);
545                 self.consume_expr(rhs);
546                 // }
547             }
548
549             ExprRepeat(base, count, _) => {
550                 self.consume_expr(base);
551                 self.consume_expr(count);
552             }
553
554             ExprDoBody(base) => {
555                 self.use_expr(base, comp_mode);
556             }
557
558             ExprFnBlock(ref decl, ref body) => {
559                 for a in decl.inputs.iter() {
560                     self.use_pat(a.pat);
561                 }
562                 let cap_vars = self.compute_captures(expr.id);
563                 self.move_maps.capture_map.insert(expr.id, cap_vars);
564                 self.consume_block(body);
565             }
566
567             ExprVstore(base, _) => {
568                 self.use_expr(base, comp_mode);
569             }
570
571             ExprMac(*) => {
572                 self.tcx.sess.span_bug(
573                     expr.span,
574                     "macro expression remains after expansion");
575             }
576         }
577     }
578
579     pub fn use_overloaded_operator(&mut self,
580                                    expr: &Expr,
581                                    receiver_expr: @Expr,
582                                    arg_exprs: &[@Expr])
583                                    -> bool {
584         if !self.method_map.contains_key(&expr.id) {
585             return false;
586         }
587
588         self.use_receiver(receiver_expr);
589
590         // for overloaded operatrs, we are always passing in a
591         // borrowed pointer, so it's always read mode:
592         for arg_expr in arg_exprs.iter() {
593             self.use_expr(*arg_expr, Read);
594         }
595
596         return true;
597     }
598
599     pub fn consume_arm(&mut self, arm: &Arm) {
600         for pat in arm.pats.iter() {
601             self.use_pat(*pat);
602         }
603
604         for guard in arm.guard.iter() {
605             self.consume_expr(*guard);
606         }
607
608         self.consume_block(&arm.body);
609     }
610
611     pub fn use_pat(&mut self, pat: @Pat) {
612         /*!
613          *
614          * Decides whether each binding in a pattern moves the value
615          * into itself or not based on its type and annotation.
616          */
617
618         do pat_bindings(self.tcx.def_map, pat) |bm, id, _span, path| {
619             let binding_moves = match bm {
620                 BindByRef(_) => false,
621                 BindByValue(_) => {
622                     let pat_ty = ty::node_id_to_type(self.tcx, id);
623                     debug!("pattern {:?} {} type is {}",
624                            id,
625                            ast_util::path_to_ident(path).repr(self.tcx),
626                            pat_ty.repr(self.tcx));
627                     ty::type_moves_by_default(self.tcx, pat_ty)
628                 }
629             };
630
631             debug!("pattern binding {:?}: bm={:?}, binding_moves={}",
632                    id, bm, binding_moves);
633
634             if binding_moves {
635                 self.move_maps.moves_map.insert(id);
636             }
637         }
638     }
639
640     pub fn use_receiver(&mut self,
641                         receiver_expr: @Expr) {
642         self.use_fn_arg(receiver_expr);
643     }
644
645     pub fn use_fn_args(&mut self,
646                        _: NodeId,
647                        arg_exprs: &[@Expr]) {
648         //! Uses the argument expressions.
649         for arg_expr in arg_exprs.iter() {
650             self.use_fn_arg(*arg_expr);
651         }
652     }
653
654     pub fn use_fn_arg(&mut self, arg_expr: @Expr) {
655         //! Uses the argument.
656         self.consume_expr(arg_expr)
657     }
658
659     pub fn arms_have_by_move_bindings(&mut self,
660                                       moves_map: MovesMap,
661                                       arms: &[Arm])
662                                       -> Option<@Pat> {
663         let mut ret = None;
664         for arm in arms.iter() {
665             for &pat in arm.pats.iter() {
666                 let cont = do ast_util::walk_pat(pat) |p| {
667                     if moves_map.contains(&p.id) {
668                         ret = Some(p);
669                         false
670                     } else {
671                         true
672                     }
673                 };
674                 if !cont { return ret }
675             }
676         }
677         ret
678     }
679
680     pub fn compute_captures(&mut self, fn_expr_id: NodeId) -> @[CaptureVar] {
681         debug!("compute_capture_vars(fn_expr_id={:?})", fn_expr_id);
682         let _indenter = indenter();
683
684         let fn_ty = ty::node_id_to_type(self.tcx, fn_expr_id);
685         let sigil = ty::ty_closure_sigil(fn_ty);
686         let freevars = freevars::get_freevars(self.tcx, fn_expr_id);
687         if sigil == BorrowedSigil {
688             // &fn() captures everything by ref
689             at_vec::from_fn(freevars.len(), |i| {
690                 let fvar = &freevars[i];
691                 CaptureVar {def: fvar.def, span: fvar.span, mode: CapRef}
692             })
693         } else {
694             // @fn() and ~fn() capture by copy or by move depending on type
695             at_vec::from_fn(freevars.len(), |i| {
696                 let fvar = &freevars[i];
697                 let fvar_def_id = ast_util::def_id_of_def(fvar.def).node;
698                 let fvar_ty = ty::node_id_to_type(self.tcx, fvar_def_id);
699                 debug!("fvar_def_id={:?} fvar_ty={}",
700                        fvar_def_id, ppaux::ty_to_str(self.tcx, fvar_ty));
701                 let mode = if ty::type_moves_by_default(self.tcx, fvar_ty) {
702                     CapMove
703                 } else {
704                     CapCopy
705                 };
706                 CaptureVar {def: fvar.def, span: fvar.span, mode:mode}
707             })
708         }
709     }
710 }