]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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; | |
85aaf69f | 19 | use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; |
1a4d82fc | 20 | use rustc::middle::ty; |
62682a34 | 21 | |
1a4d82fc JJ |
22 | use std::rc::Rc; |
23 | use syntax::ast; | |
24 | use syntax::codemap::Span; | |
e9174d1e | 25 | use rustc_front::hir; |
1a4d82fc JJ |
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) { | |
c1a9b12d | 39 | let ty = bccx.tcx.node_id_to_type(var_id); |
1a4d82fc JJ |
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>, | |
e9174d1e | 66 | move_pat: &hir::Pat, |
1a4d82fc JJ |
67 | cmt: mc::cmt<'tcx>, |
68 | mode: euv::MatchMode) { | |
69 | let tcx = bccx.tcx; | |
62682a34 SL |
70 | debug!("gather_match_variant(move_pat={}, cmt={:?}, mode={:?})", |
71 | move_pat.id, cmt, mode); | |
1a4d82fc JJ |
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>, | |
e9174d1e | 97 | move_pat: &hir::Pat, |
1a4d82fc JJ |
98 | cmt: mc::cmt<'tcx>) { |
99 | let pat_span_path_opt = match move_pat.node { | |
e9174d1e | 100 | hir::PatIdent(_, ref path1, _) => { |
1a4d82fc | 101 | Some(MoveSpanAndPath{span: move_pat.span, |
b039eaaf | 102 | name: path1.node.name}) |
1a4d82fc JJ |
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>) { | |
62682a34 SL |
119 | debug!("gather_move(move_id={}, cmt={:?})", |
120 | move_info.id, move_info.cmt); | |
1a4d82fc JJ |
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) => { | |
62682a34 | 126 | debug!("illegal_move_origin={:?}", illegal_move_origin); |
1a4d82fc JJ |
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 => { | |
62682a34 | 141 | // move from rvalue or raw pointer, hence ok |
1a4d82fc JJ |
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 | ||
85aaf69f | 161 | // (keep in sync with move_error::report_cannot_move_out_of ) |
1a4d82fc JJ |
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, _) | | |
85aaf69f SL |
180 | mc::cat_interior(ref b, mc::InteriorField(_)) | |
181 | mc::cat_interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { | |
1a4d82fc | 182 | match b.ty.sty { |
e9174d1e SL |
183 | ty::TyStruct(def, _) | ty::TyEnum(def, _) => { |
184 | if def.has_dtor() { | |
1a4d82fc JJ |
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 | ||
85aaf69f SL |
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 | ||
1a4d82fc JJ |
201 | mc::cat_deref(ref b, _, mc::Unique) => { |
202 | check_and_get_illegal_move_origin(bccx, b) | |
203 | } | |
204 | } | |
205 | } |