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 mc = middle::mem_categorization;
12 use middle::borrowck::BorrowckCtxt;
13 use middle::ty;
14
15 use std::cell::RefCell;
16 use syntax::ast;
17 use syntax::codemap;
18 use syntax::print::pprust;
19 use util::ppaux::UserString;
20
21 pub struct MoveErrorCollector {
22 errors: RefCell<Vec<MoveError>>
23 }
24
25 impl MoveErrorCollector {
26 pub fn new() -> MoveErrorCollector {
27 MoveErrorCollector {
28 errors: RefCell::new(Vec::new())
29 }
30 }
31
32 pub fn add_error(&self, error: MoveError) {
33 self.errors.borrow_mut().push(error);
34 }
35
36 pub fn report_potential_errors(&self, bccx: &BorrowckCtxt) {
37 report_move_errors(bccx, self.errors.borrow().deref())
38 }
39 }
40
41 pub struct MoveError {
42 move_from: mc::cmt,
43 move_to: Option<MoveSpanAndPath>
44 }
45
46 impl MoveError {
47 pub fn with_move_info(move_from: mc::cmt,
48 move_to: Option<MoveSpanAndPath>)
49 -> MoveError {
50 MoveError {
51 move_from: move_from,
52 move_to: move_to,
53 }
54 }
55 }
56
57 #[deriving(Clone)]
58 pub struct MoveSpanAndPath {
59 span: codemap::Span,
60 path: ast::Path
61 }
62
63 impl MoveSpanAndPath {
64 pub fn with_span_and_path(span: codemap::Span,
65 path: ast::Path)
66 -> MoveSpanAndPath {
67 MoveSpanAndPath {
68 span: span,
69 path: path,
70 }
71 }
72 }
73
74 pub struct GroupedMoveErrors {
75 move_from: mc::cmt,
76 move_to_places: Vec<MoveSpanAndPath>
77 }
78
79 fn report_move_errors(bccx: &BorrowckCtxt, errors: &Vec<MoveError>) {
80 let grouped_errors = group_errors_with_same_origin(errors);
81 for error in grouped_errors.iter() {
82 report_cannot_move_out_of(bccx, error.move_from.clone());
83 let mut is_first_note = true;
84 for move_to in error.move_to_places.iter() {
85 note_move_destination(bccx, move_to.span,
86 &move_to.path, is_first_note);
87 is_first_note = false;
88 }
89 }
90 }
91
92 fn group_errors_with_same_origin(errors: &Vec<MoveError>)
93 -> Vec<GroupedMoveErrors> {
94 let mut grouped_errors = Vec::new();
95 for error in errors.iter() {
96 append_to_grouped_errors(&mut grouped_errors, error)
97 }
98 return grouped_errors;
99
100 fn append_to_grouped_errors(grouped_errors: &mut Vec<GroupedMoveErrors>,
101 error: &MoveError) {
102 let move_from_id = error.move_from.id;
103 debug!("append_to_grouped_errors(move_from_id={})", move_from_id);
104 let move_to = if error.move_to.is_some() {
105 vec!(error.move_to.clone().unwrap())
106 } else {
107 Vec::new()
108 };
109 for ge in grouped_errors.mut_iter() {
110 if move_from_id == ge.move_from.id && error.move_to.is_some() {
111 debug!("appending move_to to list");
112 ge.move_to_places.push_all_move(move_to);
113 return
114 }
115 }
116 debug!("found a new move from location");
117 grouped_errors.push(GroupedMoveErrors {
118 move_from: error.move_from.clone(),
119 move_to_places: move_to
120 })
121 }
122 }
123
124 fn report_cannot_move_out_of(bccx: &BorrowckCtxt, move_from: mc::cmt) {
125 match move_from.cat {
126 mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
127 mc::cat_deref(_, _, mc::GcPtr) |
128 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
129 mc::cat_upvar(..) | mc::cat_static_item |
130 mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
131 bccx.span_err(
132 move_from.span,
133 format!("cannot move out of {}",
134 bccx.cmt_to_str(&*move_from)));
135 }
136
137 mc::cat_downcast(ref b) |
138 mc::cat_interior(ref b, _) => {
139 match ty::get(b.ty).sty {
140 ty::ty_struct(did, _)
141 | ty::ty_enum(did, _) if ty::has_dtor(bccx.tcx, did) => {
142 bccx.span_err(
143 move_from.span,
144 format!("cannot move out of type `{}`, \
145 which defines the `Drop` trait",
146 b.ty.user_string(bccx.tcx)));
147 },
148 _ => fail!("this path should not cause illegal move")
149 }
150 }
151 _ => fail!("this path should not cause illegal move")
152 }
153 }
154
155 fn note_move_destination(bccx: &BorrowckCtxt,
156 move_to_span: codemap::Span,
157 pat_ident_path: &ast::Path,
158 is_first_note: bool) {
159 let pat_name = pprust::path_to_str(pat_ident_path);
160 if is_first_note {
161 bccx.span_note(
162 move_to_span,
163 format!("attempting to move value to here (to prevent the move, \
164 use `ref {0}` or `ref mut {0}` to capture value by \
165 reference)",
166 pat_name));
167 } else {
168 bccx.span_note(move_to_span,
169 format!("and here (use `ref {0}` or `ref mut {0}`)",
170 pat_name));
171 }
172 }
librustc/middle/borrowck/gather_loans/move_error.rs:57:19-57:19 -struct- definition:
pub struct MoveSpanAndPath {
span: codemap::Span,
path: ast::Path
references:- 1166: -> MoveSpanAndPath {
67: MoveSpanAndPath {
68: span: span,
--
75: move_from: mc::cmt,
76: move_to_places: Vec<MoveSpanAndPath>
77: }
librustc/middle/borrowck/gather_loans/gather_moves.rs:
31: cmt: mc::cmt,
32: span_path_opt: Option<MoveSpanAndPath>
33: }
librustc/middle/borrowck/gather_loans/move_error.rs:
65: path: ast::Path)
66: -> MoveSpanAndPath {
67: MoveSpanAndPath {
librustc/middle/borrowck/gather_loans/move_error.rs:40:1-40:1 -struct- definition:
pub struct MoveError {
move_from: mc::cmt,
move_to: Option<MoveSpanAndPath>
references:- 849: -> MoveError {
50: MoveError {
51: move_from: move_from,
--
92: fn group_errors_with_same_origin(errors: &Vec<MoveError>)
93: -> Vec<GroupedMoveErrors> {
--
100: fn append_to_grouped_errors(grouped_errors: &mut Vec<GroupedMoveErrors>,
101: error: &MoveError) {
102: let move_from_id = error.move_from.id;
librustc/middle/borrowck/gather_loans/move_error.rs:20:1-20:1 -struct- definition:
pub struct MoveErrorCollector {
errors: RefCell<Vec<MoveError>>
}
references:- 726: pub fn new() -> MoveErrorCollector {
27: MoveErrorCollector {
28: errors: RefCell::new(Vec::new())
librustc/middle/borrowck/gather_loans/mod.rs:
62: move_data: move_data::MoveData,
63: move_error_collector: move_error::MoveErrorCollector,
64: all_loans: Vec<Loan>,
librustc/middle/borrowck/gather_loans/gather_moves.rs:
80: move_data: &MoveData,
81: move_error_collector: &MoveErrorCollector,
82: move_info: GatherMoveInfo) {
librustc/middle/borrowck/gather_loans/move_error.rs:73:1-73:1 -struct- definition:
pub struct GroupedMoveErrors {
move_from: mc::cmt,
move_to_places: Vec<MoveSpanAndPath>
references:- 392: fn group_errors_with_same_origin(errors: &Vec<MoveError>)
93: -> Vec<GroupedMoveErrors> {
94: let mut grouped_errors = Vec::new();
--
100: fn append_to_grouped_errors(grouped_errors: &mut Vec<GroupedMoveErrors>,
101: error: &MoveError) {
--
116: debug!("found a new move from location");
117: grouped_errors.push(GroupedMoveErrors {
118: move_from: error.move_from.clone(),