]> git.proxmox.com Git - rustc.git/blame - src/librustc_borrowck/borrowck/gather_loans/move_error.rs
New upstream version 1.32.0~beta.2+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;
7cac9316 14use rustc::middle::mem_categorization::NoteClosureEnv;
85aaf69f 15use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
54a0048b 16use rustc::ty;
ea8adc8c 17use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin};
1a4d82fc 18use syntax::ast;
3157f602 19use syntax_pos;
b7449926 20use errors::{DiagnosticBuilder, Applicability};
7cac9316 21use borrowck::gather_loans::gather_moves::PatternSource;
1a4d82fc
JJ
22
23pub struct MoveErrorCollector<'tcx> {
92a42be0 24 errors: Vec<MoveError<'tcx>>
1a4d82fc
JJ
25}
26
27impl<'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
43pub struct MoveError<'tcx> {
44 move_from: mc::cmt<'tcx>,
7cac9316 45 move_to: Option<MovePlace<'tcx>>
1a4d82fc
JJ
46}
47
48impl<'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 60pub 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
66pub struct GroupedMoveErrors<'tcx> {
67 move_from: mc::cmt<'tcx>,
7cac9316 68 move_to_places: Vec<MovePlace<'tcx>>
1a4d82fc
JJ
69}
70
8faf50e0 71fn 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 109fn 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 142fn 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 180fn 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}