]>
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; |
85aaf69f | 14 | use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; |
54a0048b | 15 | use rustc::ty; |
1a4d82fc | 16 | use syntax::ast; |
3157f602 XL |
17 | use syntax_pos; |
18 | use errors::DiagnosticBuilder; | |
1a4d82fc JJ |
19 | |
20 | pub struct MoveErrorCollector<'tcx> { | |
92a42be0 | 21 | errors: Vec<MoveError<'tcx>> |
1a4d82fc JJ |
22 | } |
23 | ||
24 | impl<'tcx> MoveErrorCollector<'tcx> { | |
25 | pub fn new() -> MoveErrorCollector<'tcx> { | |
26 | MoveErrorCollector { | |
92a42be0 | 27 | errors: Vec::new() |
1a4d82fc JJ |
28 | } |
29 | } | |
30 | ||
92a42be0 SL |
31 | pub fn add_error(&mut self, error: MoveError<'tcx>) { |
32 | self.errors.push(error); | |
1a4d82fc JJ |
33 | } |
34 | ||
35 | pub fn report_potential_errors<'a>(&self, bccx: &BorrowckCtxt<'a, 'tcx>) { | |
92a42be0 | 36 | report_move_errors(bccx, &self.errors) |
1a4d82fc JJ |
37 | } |
38 | } | |
39 | ||
40 | pub struct MoveError<'tcx> { | |
41 | move_from: mc::cmt<'tcx>, | |
42 | move_to: Option<MoveSpanAndPath> | |
43 | } | |
44 | ||
45 | impl<'tcx> MoveError<'tcx> { | |
46 | pub fn with_move_info(move_from: mc::cmt<'tcx>, | |
47 | move_to: Option<MoveSpanAndPath>) | |
48 | -> MoveError<'tcx> { | |
49 | MoveError { | |
50 | move_from: move_from, | |
51 | move_to: move_to, | |
52 | } | |
53 | } | |
54 | } | |
55 | ||
56 | #[derive(Clone)] | |
57 | pub struct MoveSpanAndPath { | |
3157f602 | 58 | pub span: syntax_pos::Span, |
b039eaaf | 59 | pub name: ast::Name, |
1a4d82fc JJ |
60 | } |
61 | ||
62 | pub struct GroupedMoveErrors<'tcx> { | |
63 | move_from: mc::cmt<'tcx>, | |
64 | move_to_places: Vec<MoveSpanAndPath> | |
65 | } | |
66 | ||
67 | fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
68 | errors: &Vec<MoveError<'tcx>>) { | |
69 | let grouped_errors = group_errors_with_same_origin(errors); | |
85aaf69f | 70 | for error in &grouped_errors { |
9cc50fc6 | 71 | let mut err = report_cannot_move_out_of(bccx, error.move_from.clone()); |
1a4d82fc | 72 | let mut is_first_note = true; |
85aaf69f | 73 | for move_to in &error.move_to_places { |
a7813a04 | 74 | err = note_move_destination(err, move_to.span, |
b039eaaf | 75 | move_to.name, is_first_note); |
1a4d82fc JJ |
76 | is_first_note = false; |
77 | } | |
9cc50fc6 | 78 | err.emit(); |
1a4d82fc JJ |
79 | } |
80 | } | |
81 | ||
82 | fn group_errors_with_same_origin<'tcx>(errors: &Vec<MoveError<'tcx>>) | |
83 | -> Vec<GroupedMoveErrors<'tcx>> { | |
84 | let mut grouped_errors = Vec::new(); | |
85aaf69f | 85 | for error in errors { |
1a4d82fc JJ |
86 | append_to_grouped_errors(&mut grouped_errors, error) |
87 | } | |
88 | return grouped_errors; | |
89 | ||
90 | fn append_to_grouped_errors<'tcx>(grouped_errors: &mut Vec<GroupedMoveErrors<'tcx>>, | |
91 | error: &MoveError<'tcx>) { | |
92 | let move_from_id = error.move_from.id; | |
93 | debug!("append_to_grouped_errors(move_from_id={})", move_from_id); | |
94 | let move_to = if error.move_to.is_some() { | |
c30ab7b3 | 95 | vec![error.move_to.clone().unwrap()] |
1a4d82fc JJ |
96 | } else { |
97 | Vec::new() | |
98 | }; | |
85aaf69f | 99 | for ge in &mut *grouped_errors { |
1a4d82fc JJ |
100 | if move_from_id == ge.move_from.id && error.move_to.is_some() { |
101 | debug!("appending move_to to list"); | |
62682a34 | 102 | ge.move_to_places.extend(move_to); |
1a4d82fc JJ |
103 | return |
104 | } | |
105 | } | |
106 | debug!("found a new move from location"); | |
107 | grouped_errors.push(GroupedMoveErrors { | |
108 | move_from: error.move_from.clone(), | |
109 | move_to_places: move_to | |
110 | }) | |
111 | } | |
112 | } | |
113 | ||
85aaf69f | 114 | // (keep in sync with gather_moves::check_and_get_illegal_move_origin ) |
1a4d82fc | 115 | fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, |
9cc50fc6 SL |
116 | move_from: mc::cmt<'tcx>) |
117 | -> DiagnosticBuilder<'a> { | |
1a4d82fc | 118 | match move_from.cat { |
9e0c209e SL |
119 | Categorization::Deref(.., mc::BorrowedPtr(..)) | |
120 | Categorization::Deref(.., mc::Implicit(..)) | | |
121 | Categorization::Deref(.., mc::UnsafePtr(..)) | | |
92a42be0 | 122 | Categorization::StaticItem => { |
a7813a04 | 123 | let mut err = struct_span_err!(bccx, move_from.span, E0507, |
9cc50fc6 | 124 | "cannot move out of {}", |
a7813a04 XL |
125 | move_from.descriptive_string(bccx.tcx)); |
126 | err.span_label( | |
127 | move_from.span, | |
128 | &format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx)) | |
129 | ); | |
130 | err | |
1a4d82fc JJ |
131 | } |
132 | ||
9e0c209e SL |
133 | Categorization::Interior(ref b, mc::InteriorElement(ik, _)) => { |
134 | match (&b.ty.sty, ik) { | |
135 | (&ty::TySlice(..), _) | | |
136 | (_, Kind::Index) => { | |
137 | let mut err = struct_span_err!(bccx, move_from.span, E0508, | |
138 | "cannot move out of type `{}`, \ | |
139 | a non-copy array", | |
140 | b.ty); | |
141 | err.span_label(move_from.span, &format!("cannot move out of here")); | |
142 | err | |
143 | } | |
144 | (_, Kind::Pattern) => { | |
145 | span_bug!(move_from.span, "this path should not cause illegal move"); | |
146 | } | |
85aaf69f SL |
147 | } |
148 | } | |
149 | ||
92a42be0 SL |
150 | Categorization::Downcast(ref b, _) | |
151 | Categorization::Interior(ref b, mc::InteriorField(_)) => { | |
1a4d82fc | 152 | match b.ty.sty { |
9e0c209e | 153 | ty::TyAdt(def, _) if def.has_dtor() => { |
a7813a04 XL |
154 | let mut err = struct_span_err!(bccx, move_from.span, E0509, |
155 | "cannot move out of type `{}`, \ | |
156 | which implements the `Drop` trait", | |
157 | b.ty); | |
158 | err.span_label(move_from.span, &format!("cannot move out of here")); | |
159 | err | |
1a4d82fc JJ |
160 | }, |
161 | _ => { | |
54a0048b | 162 | span_bug!(move_from.span, "this path should not cause illegal move"); |
1a4d82fc JJ |
163 | } |
164 | } | |
165 | } | |
166 | _ => { | |
54a0048b | 167 | span_bug!(move_from.span, "this path should not cause illegal move"); |
1a4d82fc JJ |
168 | } |
169 | } | |
170 | } | |
171 | ||
a7813a04 | 172 | fn note_move_destination(mut err: DiagnosticBuilder, |
3157f602 | 173 | move_to_span: syntax_pos::Span, |
b039eaaf | 174 | pat_name: ast::Name, |
a7813a04 | 175 | is_first_note: bool) -> DiagnosticBuilder { |
1a4d82fc | 176 | if is_first_note { |
a7813a04 | 177 | err.span_label( |
1a4d82fc | 178 | move_to_span, |
a7813a04 | 179 | &format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`", |
9cc50fc6 | 180 | pat_name)); |
a7813a04 | 181 | err |
1a4d82fc | 182 | } else { |
a7813a04 XL |
183 | err.span_label(move_to_span, |
184 | &format!("...and here (use `ref {0}` or `ref mut {0}`)", | |
c34b1796 | 185 | pat_name)); |
a7813a04 | 186 | err |
1a4d82fc JJ |
187 | } |
188 | } |