]>
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; | |
92a42be0 | 19 | use rustc::middle::mem_categorization::Categorization; |
85aaf69f | 20 | use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; |
54a0048b | 21 | use rustc::ty; |
62682a34 | 22 | |
1a4d82fc JJ |
23 | use std::rc::Rc; |
24 | use syntax::ast; | |
3157f602 | 25 | use syntax_pos::Span; |
54a0048b | 26 | use rustc::hir::{self, PatKind}; |
1a4d82fc JJ |
27 | |
28 | struct GatherMoveInfo<'tcx> { | |
29 | id: ast::NodeId, | |
30 | kind: MoveKind, | |
31 | cmt: mc::cmt<'tcx>, | |
32 | span_path_opt: Option<MoveSpanAndPath> | |
33 | } | |
34 | ||
35 | pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
36 | move_data: &MoveData<'tcx>, | |
37 | decl_id: ast::NodeId, | |
38 | _decl_span: Span, | |
39 | var_id: ast::NodeId) { | |
c30ab7b3 | 40 | let ty = bccx.tcx.tables().node_id_to_type(var_id); |
1a4d82fc JJ |
41 | let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty)); |
42 | move_data.add_move(bccx.tcx, loan_path, decl_id, Declared); | |
43 | } | |
44 | ||
45 | pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
46 | move_data: &MoveData<'tcx>, | |
92a42be0 | 47 | move_error_collector: &mut MoveErrorCollector<'tcx>, |
1a4d82fc JJ |
48 | move_expr_id: ast::NodeId, |
49 | cmt: mc::cmt<'tcx>, | |
50 | move_reason: euv::MoveReason) { | |
51 | let kind = match move_reason { | |
52 | euv::DirectRefMove | euv::PatBindingMove => MoveExpr, | |
53 | euv::CaptureMove => Captured | |
54 | }; | |
55 | let move_info = GatherMoveInfo { | |
56 | id: move_expr_id, | |
57 | kind: kind, | |
58 | cmt: cmt, | |
59 | span_path_opt: None, | |
60 | }; | |
61 | gather_move(bccx, move_data, move_error_collector, move_info); | |
62 | } | |
63 | ||
64 | pub fn gather_match_variant<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
65 | move_data: &MoveData<'tcx>, | |
92a42be0 | 66 | _move_error_collector: &mut MoveErrorCollector<'tcx>, |
e9174d1e | 67 | move_pat: &hir::Pat, |
1a4d82fc JJ |
68 | cmt: mc::cmt<'tcx>, |
69 | mode: euv::MatchMode) { | |
70 | let tcx = bccx.tcx; | |
62682a34 SL |
71 | debug!("gather_match_variant(move_pat={}, cmt={:?}, mode={:?})", |
72 | move_pat.id, cmt, mode); | |
1a4d82fc JJ |
73 | |
74 | let opt_lp = opt_loan_path(&cmt); | |
75 | match opt_lp { | |
76 | Some(lp) => { | |
77 | match lp.kind { | |
78 | LpDowncast(ref base_lp, _) => | |
79 | move_data.add_variant_match( | |
80 | tcx, lp.clone(), move_pat.id, base_lp.clone(), mode), | |
54a0048b SL |
81 | _ => bug!("should only call gather_match_variant \ |
82 | for cat_downcast cmt"), | |
1a4d82fc JJ |
83 | } |
84 | } | |
85 | None => { | |
86 | // We get None when input to match is non-path (e.g. | |
87 | // temporary result like a function call). Since no | |
88 | // loan-path is being matched, no need to record a | |
89 | // downcast. | |
90 | return; | |
91 | } | |
92 | } | |
93 | } | |
94 | ||
95 | pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
96 | move_data: &MoveData<'tcx>, | |
92a42be0 | 97 | move_error_collector: &mut MoveErrorCollector<'tcx>, |
e9174d1e | 98 | move_pat: &hir::Pat, |
1a4d82fc JJ |
99 | cmt: mc::cmt<'tcx>) { |
100 | let pat_span_path_opt = match move_pat.node { | |
3157f602 | 101 | PatKind::Binding(_, ref path1, _) => { |
1a4d82fc | 102 | Some(MoveSpanAndPath{span: move_pat.span, |
a7813a04 | 103 | name: path1.node}) |
1a4d82fc JJ |
104 | }, |
105 | _ => None, | |
106 | }; | |
107 | let move_info = GatherMoveInfo { | |
108 | id: move_pat.id, | |
109 | kind: MovePat, | |
110 | cmt: cmt, | |
111 | span_path_opt: pat_span_path_opt, | |
112 | }; | |
113 | gather_move(bccx, move_data, move_error_collector, move_info); | |
114 | } | |
115 | ||
116 | fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
117 | move_data: &MoveData<'tcx>, | |
92a42be0 | 118 | move_error_collector: &mut MoveErrorCollector<'tcx>, |
1a4d82fc | 119 | move_info: GatherMoveInfo<'tcx>) { |
62682a34 SL |
120 | debug!("gather_move(move_id={}, cmt={:?})", |
121 | move_info.id, move_info.cmt); | |
1a4d82fc JJ |
122 | |
123 | let potentially_illegal_move = | |
124 | check_and_get_illegal_move_origin(bccx, &move_info.cmt); | |
3157f602 XL |
125 | if let Some(illegal_move_origin) = potentially_illegal_move { |
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; | |
1a4d82fc JJ |
131 | } |
132 | ||
133 | match opt_loan_path(&move_info.cmt) { | |
134 | Some(loan_path) => { | |
135 | move_data.add_move(bccx.tcx, loan_path, | |
136 | move_info.id, move_info.kind); | |
137 | } | |
138 | None => { | |
62682a34 | 139 | // move from rvalue or raw pointer, hence ok |
1a4d82fc JJ |
140 | } |
141 | } | |
142 | } | |
143 | ||
144 | pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
145 | move_data: &MoveData<'tcx>, | |
146 | assignment_id: ast::NodeId, | |
147 | assignment_span: Span, | |
148 | assignee_loan_path: Rc<LoanPath<'tcx>>, | |
149 | assignee_id: ast::NodeId, | |
150 | mode: euv::MutateMode) { | |
151 | move_data.add_assignment(bccx.tcx, | |
152 | assignee_loan_path, | |
153 | assignment_id, | |
154 | assignment_span, | |
155 | assignee_id, | |
156 | mode); | |
157 | } | |
158 | ||
85aaf69f | 159 | // (keep in sync with move_error::report_cannot_move_out_of ) |
1a4d82fc JJ |
160 | fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, |
161 | cmt: &mc::cmt<'tcx>) | |
162 | -> Option<mc::cmt<'tcx>> { | |
163 | match cmt.cat { | |
9e0c209e SL |
164 | Categorization::Deref(.., mc::BorrowedPtr(..)) | |
165 | Categorization::Deref(.., mc::Implicit(..)) | | |
166 | Categorization::Deref(.., mc::UnsafePtr(..)) | | |
92a42be0 | 167 | Categorization::StaticItem => { |
1a4d82fc JJ |
168 | Some(cmt.clone()) |
169 | } | |
170 | ||
92a42be0 SL |
171 | Categorization::Rvalue(..) | |
172 | Categorization::Local(..) | | |
173 | Categorization::Upvar(..) => { | |
1a4d82fc JJ |
174 | None |
175 | } | |
176 | ||
92a42be0 SL |
177 | Categorization::Downcast(ref b, _) | |
178 | Categorization::Interior(ref b, mc::InteriorField(_)) | | |
179 | Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { | |
1a4d82fc | 180 | match b.ty.sty { |
9e0c209e | 181 | ty::TyAdt(def, _) => { |
e9174d1e | 182 | if def.has_dtor() { |
1a4d82fc JJ |
183 | Some(cmt.clone()) |
184 | } else { | |
185 | check_and_get_illegal_move_origin(bccx, b) | |
186 | } | |
187 | } | |
9e0c209e | 188 | ty::TySlice(..) => Some(cmt.clone()), |
1a4d82fc JJ |
189 | _ => { |
190 | check_and_get_illegal_move_origin(bccx, b) | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
92a42be0 | 195 | Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => { |
85aaf69f SL |
196 | // Forbid move of arr[i] for arr: [T; 3]; see RFC 533. |
197 | Some(cmt.clone()) | |
198 | } | |
199 | ||
92a42be0 | 200 | Categorization::Deref(ref b, _, mc::Unique) => { |
1a4d82fc JJ |
201 | check_and_get_illegal_move_origin(bccx, b) |
202 | } | |
203 | } | |
204 | } |