]> git.proxmox.com Git - rustc.git/blame - src/librustc_borrowck/borrowck/gather_loans/move_error.rs
New upstream version 1.16.0+dfsg1
[rustc.git] / src / librustc_borrowck / borrowck / gather_loans / move_error.rs
CommitLineData
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
11use borrowck::BorrowckCtxt;
12use rustc::middle::mem_categorization as mc;
92a42be0 13use rustc::middle::mem_categorization::Categorization;
85aaf69f 14use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
54a0048b 15use rustc::ty;
1a4d82fc 16use syntax::ast;
3157f602
XL
17use syntax_pos;
18use errors::DiagnosticBuilder;
1a4d82fc
JJ
19
20pub struct MoveErrorCollector<'tcx> {
92a42be0 21 errors: Vec<MoveError<'tcx>>
1a4d82fc
JJ
22}
23
24impl<'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
40pub struct MoveError<'tcx> {
41 move_from: mc::cmt<'tcx>,
42 move_to: Option<MoveSpanAndPath>
43}
44
45impl<'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)]
57pub struct MoveSpanAndPath {
3157f602 58 pub span: syntax_pos::Span,
b039eaaf 59 pub name: ast::Name,
1a4d82fc
JJ
60}
61
62pub struct GroupedMoveErrors<'tcx> {
63 move_from: mc::cmt<'tcx>,
64 move_to_places: Vec<MoveSpanAndPath>
65}
66
67fn 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
82fn 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 115fn 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 172fn 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}