]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/borrowck/gather_loans/gather_moves.rs
Doc says to avoid mixing allocator instead of forbiding it
[rust.git] / src / librustc / middle / borrowck / gather_loans / gather_moves.rs
1 // Copyright 2012-2013 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  * Computes moves.
13  */
14
15 use middle::borrowck::*;
16 use middle::borrowck::gather_loans::move_error::MoveSpanAndPath;
17 use middle::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
18 use middle::borrowck::move_data::*;
19 use middle::expr_use_visitor as euv;
20 use middle::mem_categorization as mc;
21 use middle::ty;
22 use syntax::ast;
23 use syntax::codemap::Span;
24 use util::ppaux::Repr;
25
26 use std::rc::Rc;
27
28 struct GatherMoveInfo {
29     id: ast::NodeId,
30     kind: MoveKind,
31     cmt: mc::cmt,
32     span_path_opt: Option<MoveSpanAndPath>
33 }
34
35 pub fn gather_decl(bccx: &BorrowckCtxt,
36                    move_data: &MoveData,
37                    decl_id: ast::NodeId,
38                    _decl_span: Span,
39                    var_id: ast::NodeId) {
40     let loan_path = Rc::new(LpVar(var_id));
41     move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
42 }
43
44 pub fn gather_move_from_expr(bccx: &BorrowckCtxt,
45                              move_data: &MoveData,
46                              move_error_collector: &MoveErrorCollector,
47                              move_expr_id: ast::NodeId,
48                              cmt: mc::cmt,
49                              move_reason: euv::MoveReason) {
50     let kind = match move_reason {
51         euv::DirectRefMove | euv::PatBindingMove => MoveExpr,
52         euv::CaptureMove => Captured
53     };
54     let move_info = GatherMoveInfo {
55         id: move_expr_id,
56         kind: kind,
57         cmt: cmt,
58         span_path_opt: None,
59     };
60     gather_move(bccx, move_data, move_error_collector, move_info);
61 }
62
63 pub fn gather_move_from_pat(bccx: &BorrowckCtxt,
64                             move_data: &MoveData,
65                             move_error_collector: &MoveErrorCollector,
66                             move_pat: &ast::Pat,
67                             cmt: mc::cmt) {
68     let pat_span_path_opt = match move_pat.node {
69         ast::PatIdent(_, ref path1, _) => {
70             Some(MoveSpanAndPath{span: move_pat.span,
71                                  ident: path1.node})
72         },
73         _ => None,
74     };
75     let move_info = GatherMoveInfo {
76         id: move_pat.id,
77         kind: MovePat,
78         cmt: cmt,
79         span_path_opt: pat_span_path_opt,
80     };
81     gather_move(bccx, move_data, move_error_collector, move_info);
82 }
83
84 fn gather_move(bccx: &BorrowckCtxt,
85                move_data: &MoveData,
86                move_error_collector: &MoveErrorCollector,
87                move_info: GatherMoveInfo) {
88     debug!("gather_move(move_id={}, cmt={})",
89            move_info.id, move_info.cmt.repr(bccx.tcx));
90
91     let potentially_illegal_move =
92                 check_and_get_illegal_move_origin(bccx, &move_info.cmt);
93     match potentially_illegal_move {
94         Some(illegal_move_origin) => {
95             debug!("illegal_move_origin={}", illegal_move_origin.repr(bccx.tcx));
96             let error = MoveError::with_move_info(illegal_move_origin,
97                                                   move_info.span_path_opt);
98             move_error_collector.add_error(error);
99             return
100         }
101         None => ()
102     }
103
104     match opt_loan_path(&move_info.cmt) {
105         Some(loan_path) => {
106             move_data.add_move(bccx.tcx, loan_path,
107                                move_info.id, move_info.kind);
108         }
109         None => {
110             // move from rvalue or unsafe pointer, hence ok
111         }
112     }
113 }
114
115 pub fn gather_assignment(bccx: &BorrowckCtxt,
116                          move_data: &MoveData,
117                          assignment_id: ast::NodeId,
118                          assignment_span: Span,
119                          assignee_loan_path: Rc<LoanPath>,
120                          assignee_id: ast::NodeId,
121                          mode: euv::MutateMode) {
122     move_data.add_assignment(bccx.tcx,
123                              assignee_loan_path,
124                              assignment_id,
125                              assignment_span,
126                              assignee_id,
127                              mode);
128 }
129
130 fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
131                                      cmt: &mc::cmt) -> Option<mc::cmt> {
132     match cmt.cat {
133         mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
134         mc::cat_deref(_, _, mc::Implicit(..)) |
135         mc::cat_deref(_, _, mc::GcPtr) |
136         mc::cat_deref(_, _, mc::UnsafePtr(..)) |
137         mc::cat_upvar(..) | mc::cat_static_item |
138         mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
139             Some(cmt.clone())
140         }
141
142         // Can move out of captured upvars only if the destination closure
143         // type is 'once'. 1-shot stack closures emit the copied_upvar form
144         // (see mem_categorization.rs).
145         mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, .. }) => {
146             None
147         }
148
149         mc::cat_rvalue(..) |
150         mc::cat_local(..) |
151         mc::cat_arg(..) => {
152             None
153         }
154
155         mc::cat_downcast(ref b) |
156         mc::cat_interior(ref b, _) => {
157             match ty::get(b.ty).sty {
158                 ty::ty_struct(did, _) | ty::ty_enum(did, _) => {
159                     if ty::has_dtor(bccx.tcx, did) {
160                         Some(cmt.clone())
161                     } else {
162                         check_and_get_illegal_move_origin(bccx, b)
163                     }
164                 }
165                 _ => {
166                     check_and_get_illegal_move_origin(bccx, b)
167                 }
168             }
169         }
170
171         mc::cat_deref(ref b, _, mc::OwnedPtr) |
172         mc::cat_discr(ref b, _) => {
173             check_and_get_illegal_move_origin(bccx, b)
174         }
175     }
176 }