]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2014 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 | use borrowck::BorrowckCtxt; | |
12 | use rustc::middle::mem_categorization as mc; | |
92a42be0 | 13 | use rustc::middle::mem_categorization::Categorization; |
7cac9316 | 14 | use rustc::middle::mem_categorization::NoteClosureEnv; |
85aaf69f | 15 | use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; |
54a0048b | 16 | use rustc::ty; |
ea8adc8c | 17 | use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; |
1a4d82fc | 18 | use syntax::ast; |
3157f602 | 19 | use syntax_pos; |
b7449926 | 20 | use errors::{DiagnosticBuilder, Applicability}; |
7cac9316 | 21 | use borrowck::gather_loans::gather_moves::PatternSource; |
1a4d82fc JJ |
22 | |
23 | pub struct MoveErrorCollector<'tcx> { | |
92a42be0 | 24 | errors: Vec<MoveError<'tcx>> |
1a4d82fc JJ |
25 | } |
26 | ||
27 | impl<'tcx> MoveErrorCollector<'tcx> { | |
28 | pub fn new() -> MoveErrorCollector<'tcx> { | |
29 | MoveErrorCollector { | |
92a42be0 | 30 | errors: Vec::new() |
1a4d82fc JJ |
31 | } |
32 | } | |
33 | ||
92a42be0 SL |
34 | pub fn add_error(&mut self, error: MoveError<'tcx>) { |
35 | self.errors.push(error); | |
1a4d82fc JJ |
36 | } |
37 | ||
38 | pub fn report_potential_errors<'a>(&self, bccx: &BorrowckCtxt<'a, 'tcx>) { | |
92a42be0 | 39 | report_move_errors(bccx, &self.errors) |
1a4d82fc JJ |
40 | } |
41 | } | |
42 | ||
43 | pub struct MoveError<'tcx> { | |
44 | move_from: mc::cmt<'tcx>, | |
7cac9316 | 45 | move_to: Option<MovePlace<'tcx>> |
1a4d82fc JJ |
46 | } |
47 | ||
48 | impl<'tcx> MoveError<'tcx> { | |
49 | pub fn with_move_info(move_from: mc::cmt<'tcx>, | |
7cac9316 | 50 | move_to: Option<MovePlace<'tcx>>) |
1a4d82fc JJ |
51 | -> MoveError<'tcx> { |
52 | MoveError { | |
3b2f2976 XL |
53 | move_from, |
54 | move_to, | |
1a4d82fc JJ |
55 | } |
56 | } | |
57 | } | |
58 | ||
59 | #[derive(Clone)] | |
7cac9316 | 60 | pub struct MovePlace<'tcx> { |
3157f602 | 61 | pub span: syntax_pos::Span, |
b039eaaf | 62 | pub name: ast::Name, |
7cac9316 | 63 | pub pat_source: PatternSource<'tcx>, |
1a4d82fc JJ |
64 | } |
65 | ||
66 | pub struct GroupedMoveErrors<'tcx> { | |
67 | move_from: mc::cmt<'tcx>, | |
7cac9316 | 68 | move_to_places: Vec<MovePlace<'tcx>> |
1a4d82fc JJ |
69 | } |
70 | ||
8faf50e0 | 71 | fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveError<'tcx>]) { |
1a4d82fc | 72 | let grouped_errors = group_errors_with_same_origin(errors); |
85aaf69f | 73 | for error in &grouped_errors { |
9cc50fc6 | 74 | let mut err = report_cannot_move_out_of(bccx, error.move_from.clone()); |
1a4d82fc | 75 | let mut is_first_note = true; |
7cac9316 XL |
76 | match error.move_to_places.get(0) { |
77 | Some(&MovePlace { pat_source: PatternSource::LetDecl(ref e), .. }) => { | |
78 | // ignore patterns that are found at the top-level of a `let`; | |
79 | // see `get_pattern_source()` for details | |
80 | let initializer = | |
81 | e.init.as_ref().expect("should have an initializer to get an error"); | |
b7449926 XL |
82 | if let Ok(snippet) = bccx.tcx.sess.source_map().span_to_snippet(initializer.span) { |
83 | err.span_suggestion_with_applicability( | |
84 | initializer.span, | |
85 | "consider using a reference instead", | |
86 | format!("&{}", snippet), | |
87 | Applicability::MaybeIncorrect // using a reference may not be the right fix | |
88 | ); | |
7cac9316 XL |
89 | } |
90 | } | |
91 | _ => { | |
92 | for move_to in &error.move_to_places { | |
93 | ||
94 | err = note_move_destination(err, move_to.span, move_to.name, is_first_note); | |
95 | is_first_note = false; | |
96 | } | |
97 | } | |
98 | } | |
99 | if let NoteClosureEnv(upvar_id) = error.move_from.note { | |
a1dfa0c6 | 100 | let var_node_id = bccx.tcx.hir.hir_to_node_id(upvar_id.var_path.hir_id); |
3b2f2976 | 101 | err.span_label(bccx.tcx.hir.span(var_node_id), |
7cac9316 | 102 | "captured outer variable"); |
1a4d82fc | 103 | } |
9cc50fc6 | 104 | err.emit(); |
8faf50e0 | 105 | bccx.signal_error(); |
1a4d82fc JJ |
106 | } |
107 | } | |
108 | ||
8faf50e0 | 109 | fn group_errors_with_same_origin<'tcx>(errors: &[MoveError<'tcx>]) |
1a4d82fc JJ |
110 | -> Vec<GroupedMoveErrors<'tcx>> { |
111 | let mut grouped_errors = Vec::new(); | |
85aaf69f | 112 | for error in errors { |
1a4d82fc JJ |
113 | append_to_grouped_errors(&mut grouped_errors, error) |
114 | } | |
115 | return grouped_errors; | |
116 | ||
117 | fn append_to_grouped_errors<'tcx>(grouped_errors: &mut Vec<GroupedMoveErrors<'tcx>>, | |
118 | error: &MoveError<'tcx>) { | |
8faf50e0 XL |
119 | let move_from_id = error.move_from.hir_id; |
120 | debug!("append_to_grouped_errors(move_from_id={:?})", move_from_id); | |
1a4d82fc | 121 | let move_to = if error.move_to.is_some() { |
c30ab7b3 | 122 | vec![error.move_to.clone().unwrap()] |
1a4d82fc JJ |
123 | } else { |
124 | Vec::new() | |
125 | }; | |
85aaf69f | 126 | for ge in &mut *grouped_errors { |
8faf50e0 | 127 | if move_from_id == ge.move_from.hir_id && error.move_to.is_some() { |
1a4d82fc | 128 | debug!("appending move_to to list"); |
62682a34 | 129 | ge.move_to_places.extend(move_to); |
1a4d82fc JJ |
130 | return |
131 | } | |
132 | } | |
133 | debug!("found a new move from location"); | |
134 | grouped_errors.push(GroupedMoveErrors { | |
135 | move_from: error.move_from.clone(), | |
136 | move_to_places: move_to | |
137 | }) | |
138 | } | |
139 | } | |
140 | ||
85aaf69f | 141 | // (keep in sync with gather_moves::check_and_get_illegal_move_origin ) |
ea8adc8c | 142 | fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, |
9cc50fc6 SL |
143 | move_from: mc::cmt<'tcx>) |
144 | -> DiagnosticBuilder<'a> { | |
1a4d82fc | 145 | match move_from.cat { |
7cac9316 | 146 | Categorization::Deref(_, mc::BorrowedPtr(..)) | |
7cac9316 | 147 | Categorization::Deref(_, mc::UnsafePtr(..)) | |
a1dfa0c6 XL |
148 | Categorization::Deref(_, mc::Unique) | |
149 | Categorization::ThreadLocal(..) | | |
92a42be0 | 150 | Categorization::StaticItem => { |
ea8adc8c XL |
151 | bccx.cannot_move_out_of( |
152 | move_from.span, &move_from.descriptive_string(bccx.tcx), Origin::Ast) | |
1a4d82fc | 153 | } |
7cac9316 | 154 | Categorization::Interior(ref b, mc::InteriorElement(ik)) => { |
ea8adc8c | 155 | bccx.cannot_move_out_of_interior_noncopy( |
94b46f34 | 156 | move_from.span, b.ty, Some(ik == Kind::Index), Origin::Ast) |
85aaf69f SL |
157 | } |
158 | ||
92a42be0 SL |
159 | Categorization::Downcast(ref b, _) | |
160 | Categorization::Interior(ref b, mc::InteriorField(_)) => { | |
1a4d82fc | 161 | match b.ty.sty { |
b7449926 | 162 | ty::Adt(def, _) if def.has_dtor(bccx.tcx) => { |
ea8adc8c XL |
163 | bccx.cannot_move_out_of_interior_of_drop( |
164 | move_from.span, b.ty, Origin::Ast) | |
165 | } | |
1a4d82fc | 166 | _ => { |
54a0048b | 167 | span_bug!(move_from.span, "this path should not cause illegal move"); |
1a4d82fc JJ |
168 | } |
169 | } | |
170 | } | |
a1dfa0c6 XL |
171 | |
172 | Categorization::Rvalue(..) | | |
173 | Categorization::Local(..) | | |
174 | Categorization::Upvar(..) => { | |
54a0048b | 175 | span_bug!(move_from.span, "this path should not cause illegal move"); |
1a4d82fc JJ |
176 | } |
177 | } | |
178 | } | |
179 | ||
a7813a04 | 180 | fn note_move_destination(mut err: DiagnosticBuilder, |
3157f602 | 181 | move_to_span: syntax_pos::Span, |
b039eaaf | 182 | pat_name: ast::Name, |
a7813a04 | 183 | is_first_note: bool) -> DiagnosticBuilder { |
1a4d82fc | 184 | if is_first_note { |
a7813a04 | 185 | err.span_label( |
1a4d82fc | 186 | move_to_span, |
7cac9316 | 187 | format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`", |
9cc50fc6 | 188 | pat_name)); |
a7813a04 | 189 | err |
1a4d82fc | 190 | } else { |
a7813a04 | 191 | err.span_label(move_to_span, |
7cac9316 | 192 | format!("...and here (use `ref {0}` or `ref mut {0}`)", |
c34b1796 | 193 | pat_name)); |
a7813a04 | 194 | err |
1a4d82fc JJ |
195 | } |
196 | } |