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.
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.
11 use borrowck::BorrowckCtxt;
12 use rustc::middle::mem_categorization as mc;
13 use rustc::middle::mem_categorization::Categorization;
14 use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
15 use rustc::middle::ty;
18 use syntax::errors::DiagnosticBuilder;
21 pub struct MoveErrorCollector<'tcx> {
22 errors: Vec<MoveError<'tcx>>
25 impl<'tcx> MoveErrorCollector<'tcx> {
26 pub fn new() -> MoveErrorCollector<'tcx> {
32 pub fn add_error(&mut self, error: MoveError<'tcx>) {
33 self.errors.push(error);
36 pub fn report_potential_errors<'a>(&self, bccx: &BorrowckCtxt<'a, 'tcx>) {
37 report_move_errors(bccx, &self.errors)
41 pub struct MoveError<'tcx> {
42 move_from: mc::cmt<'tcx>,
43 move_to: Option<MoveSpanAndPath>
46 impl<'tcx> MoveError<'tcx> {
47 pub fn with_move_info(move_from: mc::cmt<'tcx>,
48 move_to: Option<MoveSpanAndPath>)
58 pub struct MoveSpanAndPath {
59 pub span: codemap::Span,
63 pub struct GroupedMoveErrors<'tcx> {
64 move_from: mc::cmt<'tcx>,
65 move_to_places: Vec<MoveSpanAndPath>
68 fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
69 errors: &Vec<MoveError<'tcx>>) {
70 let grouped_errors = group_errors_with_same_origin(errors);
71 for error in &grouped_errors {
72 let mut err = report_cannot_move_out_of(bccx, error.move_from.clone());
73 let mut is_first_note = true;
74 for move_to in &error.move_to_places {
75 note_move_destination(&mut err, move_to.span,
76 move_to.name, is_first_note);
77 is_first_note = false;
83 fn group_errors_with_same_origin<'tcx>(errors: &Vec<MoveError<'tcx>>)
84 -> Vec<GroupedMoveErrors<'tcx>> {
85 let mut grouped_errors = Vec::new();
87 append_to_grouped_errors(&mut grouped_errors, error)
89 return grouped_errors;
91 fn append_to_grouped_errors<'tcx>(grouped_errors: &mut Vec<GroupedMoveErrors<'tcx>>,
92 error: &MoveError<'tcx>) {
93 let move_from_id = error.move_from.id;
94 debug!("append_to_grouped_errors(move_from_id={})", move_from_id);
95 let move_to = if error.move_to.is_some() {
96 vec!(error.move_to.clone().unwrap())
100 for ge in &mut *grouped_errors {
101 if move_from_id == ge.move_from.id && error.move_to.is_some() {
102 debug!("appending move_to to list");
103 ge.move_to_places.extend(move_to);
107 debug!("found a new move from location");
108 grouped_errors.push(GroupedMoveErrors {
109 move_from: error.move_from.clone(),
110 move_to_places: move_to
115 // (keep in sync with gather_moves::check_and_get_illegal_move_origin )
116 fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
117 move_from: mc::cmt<'tcx>)
118 -> DiagnosticBuilder<'a> {
119 match move_from.cat {
120 Categorization::Deref(_, _, mc::BorrowedPtr(..)) |
121 Categorization::Deref(_, _, mc::Implicit(..)) |
122 Categorization::Deref(_, _, mc::UnsafePtr(..)) |
123 Categorization::StaticItem => {
124 struct_span_err!(bccx, move_from.span, E0507,
125 "cannot move out of {}",
126 move_from.descriptive_string(bccx.tcx))
129 Categorization::Interior(ref b, mc::InteriorElement(Kind::Index, _)) => {
130 let expr = bccx.tcx.map.expect_expr(move_from.id);
131 if let hir::ExprIndex(..) = expr.node {
132 struct_span_err!(bccx, move_from.span, E0508,
133 "cannot move out of type `{}`, \
134 a non-copy fixed-size array",
137 bccx.span_bug(move_from.span, "this path should not cause illegal move");
142 Categorization::Downcast(ref b, _) |
143 Categorization::Interior(ref b, mc::InteriorField(_)) => {
145 ty::TyStruct(def, _) |
146 ty::TyEnum(def, _) if def.has_dtor() => {
147 struct_span_err!(bccx, move_from.span, E0509,
148 "cannot move out of type `{}`, \
149 which defines the `Drop` trait",
153 bccx.span_bug(move_from.span, "this path should not cause illegal move");
159 bccx.span_bug(move_from.span, "this path should not cause illegal move");
165 fn note_move_destination(err: &mut DiagnosticBuilder,
166 move_to_span: codemap::Span,
168 is_first_note: bool) {
172 "attempting to move value to here");
175 &format!("to prevent the move, \
176 use `ref {0}` or `ref mut {0}` to capture value by \
180 err.span_note(move_to_span,
181 &format!("and here (use `ref {0}` or `ref mut {0}`)",