]> git.lizzy.rs Git - rust.git/blob - src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
Remove random Idents outside of libsyntax
[rust.git] / src / librustc_borrowck / 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 //! Computes moves.
12
13 use borrowck::*;
14 use borrowck::gather_loans::move_error::MoveSpanAndPath;
15 use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
16 use borrowck::move_data::*;
17 use rustc::middle::expr_use_visitor as euv;
18 use rustc::middle::mem_categorization as mc;
19 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
20 use rustc::middle::ty;
21
22 use std::rc::Rc;
23 use syntax::ast;
24 use syntax::codemap::Span;
25 use rustc_front::hir;
26
27 struct GatherMoveInfo<'tcx> {
28     id: ast::NodeId,
29     kind: MoveKind,
30     cmt: mc::cmt<'tcx>,
31     span_path_opt: Option<MoveSpanAndPath>
32 }
33
34 pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
35                              move_data: &MoveData<'tcx>,
36                              decl_id: ast::NodeId,
37                              _decl_span: Span,
38                              var_id: ast::NodeId) {
39     let ty = bccx.tcx.node_id_to_type(var_id);
40     let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty));
41     move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
42 }
43
44 pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
45                                        move_data: &MoveData<'tcx>,
46                                        move_error_collector: &MoveErrorCollector<'tcx>,
47                                        move_expr_id: ast::NodeId,
48                                        cmt: mc::cmt<'tcx>,
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_match_variant<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
64                                       move_data: &MoveData<'tcx>,
65                                       _move_error_collector: &MoveErrorCollector<'tcx>,
66                                       move_pat: &hir::Pat,
67                                       cmt: mc::cmt<'tcx>,
68                                       mode: euv::MatchMode) {
69     let tcx = bccx.tcx;
70     debug!("gather_match_variant(move_pat={}, cmt={:?}, mode={:?})",
71            move_pat.id, cmt, mode);
72
73     let opt_lp = opt_loan_path(&cmt);
74     match opt_lp {
75         Some(lp) => {
76             match lp.kind {
77                 LpDowncast(ref base_lp, _) =>
78                     move_data.add_variant_match(
79                         tcx, lp.clone(), move_pat.id, base_lp.clone(), mode),
80                 _ => panic!("should only call gather_match_variant \
81                              for cat_downcast cmt"),
82             }
83         }
84         None => {
85             // We get None when input to match is non-path (e.g.
86             // temporary result like a function call). Since no
87             // loan-path is being matched, no need to record a
88             // downcast.
89             return;
90         }
91     }
92 }
93
94 pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
95                                       move_data: &MoveData<'tcx>,
96                                       move_error_collector: &MoveErrorCollector<'tcx>,
97                                       move_pat: &hir::Pat,
98                                       cmt: mc::cmt<'tcx>) {
99     let pat_span_path_opt = match move_pat.node {
100         hir::PatIdent(_, ref path1, _) => {
101             Some(MoveSpanAndPath{span: move_pat.span,
102                                  name: path1.node.name})
103         },
104         _ => None,
105     };
106     let move_info = GatherMoveInfo {
107         id: move_pat.id,
108         kind: MovePat,
109         cmt: cmt,
110         span_path_opt: pat_span_path_opt,
111     };
112     gather_move(bccx, move_data, move_error_collector, move_info);
113 }
114
115 fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
116                          move_data: &MoveData<'tcx>,
117                          move_error_collector: &MoveErrorCollector<'tcx>,
118                          move_info: GatherMoveInfo<'tcx>) {
119     debug!("gather_move(move_id={}, cmt={:?})",
120            move_info.id, move_info.cmt);
121
122     let potentially_illegal_move =
123                 check_and_get_illegal_move_origin(bccx, &move_info.cmt);
124     match potentially_illegal_move {
125         Some(illegal_move_origin) => {
126             debug!("illegal_move_origin={:?}", illegal_move_origin);
127             let error = MoveError::with_move_info(illegal_move_origin,
128                                                   move_info.span_path_opt);
129             move_error_collector.add_error(error);
130             return
131         }
132         None => ()
133     }
134
135     match opt_loan_path(&move_info.cmt) {
136         Some(loan_path) => {
137             move_data.add_move(bccx.tcx, loan_path,
138                                move_info.id, move_info.kind);
139         }
140         None => {
141             // move from rvalue or raw pointer, hence ok
142         }
143     }
144 }
145
146 pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
147                                    move_data: &MoveData<'tcx>,
148                                    assignment_id: ast::NodeId,
149                                    assignment_span: Span,
150                                    assignee_loan_path: Rc<LoanPath<'tcx>>,
151                                    assignee_id: ast::NodeId,
152                                    mode: euv::MutateMode) {
153     move_data.add_assignment(bccx.tcx,
154                              assignee_loan_path,
155                              assignment_id,
156                              assignment_span,
157                              assignee_id,
158                              mode);
159 }
160
161 // (keep in sync with move_error::report_cannot_move_out_of )
162 fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
163                                                cmt: &mc::cmt<'tcx>)
164                                                -> Option<mc::cmt<'tcx>> {
165     match cmt.cat {
166         mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
167         mc::cat_deref(_, _, mc::Implicit(..)) |
168         mc::cat_deref(_, _, mc::UnsafePtr(..)) |
169         mc::cat_static_item => {
170             Some(cmt.clone())
171         }
172
173         mc::cat_rvalue(..) |
174         mc::cat_local(..) |
175         mc::cat_upvar(..) => {
176             None
177         }
178
179         mc::cat_downcast(ref b, _) |
180         mc::cat_interior(ref b, mc::InteriorField(_)) |
181         mc::cat_interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
182             match b.ty.sty {
183                 ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
184                     if def.has_dtor() {
185                         Some(cmt.clone())
186                     } else {
187                         check_and_get_illegal_move_origin(bccx, b)
188                     }
189                 }
190                 _ => {
191                     check_and_get_illegal_move_origin(bccx, b)
192                 }
193             }
194         }
195
196         mc::cat_interior(_, mc::InteriorElement(Kind::Index, _)) => {
197             // Forbid move of arr[i] for arr: [T; 3]; see RFC 533.
198             Some(cmt.clone())
199         }
200
201         mc::cat_deref(ref b, _, mc::Unique) => {
202             check_and_get_illegal_move_origin(bccx, b)
203         }
204     }
205 }