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
::InteriorOffsetKind
as Kind
;
14 use rustc
::middle
::ty
;
15 use rustc
::util
::ppaux
::UserString
;
16 use std
::cell
::RefCell
;
19 use syntax
::print
::pprust
;
21 pub struct MoveErrorCollector
<'tcx
> {
22 errors
: RefCell
<Vec
<MoveError
<'tcx
>>>
25 impl<'tcx
> MoveErrorCollector
<'tcx
> {
26 pub fn new() -> MoveErrorCollector
<'tcx
> {
28 errors
: RefCell
::new(Vec
::new())
32 pub fn add_error(&self, error
: MoveError
<'tcx
>) {
33 self.errors
.borrow_mut().push(error
);
36 pub fn report_potential_errors
<'a
>(&self, bccx
: &BorrowckCtxt
<'a
, 'tcx
>) {
37 report_move_errors(bccx
, &*self.errors
.borrow())
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 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(bccx
, move_to
.span
,
76 &move_to
.ident
, is_first_note
);
77 is_first_note
= false;
82 fn group_errors_with_same_origin
<'tcx
>(errors
: &Vec
<MoveError
<'tcx
>>)
83 -> Vec
<GroupedMoveErrors
<'tcx
>> {
84 let mut grouped_errors
= Vec
::new();
86 append_to_grouped_errors(&mut grouped_errors
, error
)
88 return grouped_errors
;
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() {
95 vec
!(error
.move_to
.clone().unwrap())
99 for ge
in &mut *grouped_errors
{
100 if move_from_id
== ge
.move_from
.id
&& error
.move_to
.is_some() {
101 debug
!("appending move_to to list");
102 ge
.move_to_places
.extend(move_to
.into_iter());
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
114 // (keep in sync with gather_moves::check_and_get_illegal_move_origin )
115 fn report_cannot_move_out_of
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
116 move_from
: mc
::cmt
<'tcx
>) {
117 match move_from
.cat
{
118 mc
::cat_deref(_
, _
, mc
::BorrowedPtr(..)) |
119 mc
::cat_deref(_
, _
, mc
::Implicit(..)) |
120 mc
::cat_deref(_
, _
, mc
::UnsafePtr(..)) |
121 mc
::cat_static_item
=> {
122 bccx
.span_err(move_from
.span
,
123 &format
!("cannot move out of {}",
124 move_from
.descriptive_string(bccx
.tcx
)));
127 mc
::cat_interior(ref b
, mc
::InteriorElement(Kind
::Index
, _
)) => {
128 let expr
= bccx
.tcx
.map
.expect_expr(move_from
.id
);
129 if let ast
::ExprIndex(..) = expr
.node
{
130 bccx
.span_err(move_from
.span
,
131 &format
!("cannot move out of type `{}`, \
132 a non-copy fixed-size array",
133 b
.ty
.user_string(bccx
.tcx
)));
137 mc
::cat_downcast(ref b
, _
) |
138 mc
::cat_interior(ref b
, mc
::InteriorField(_
)) => {
140 ty
::ty_struct(did
, _
) |
141 ty
::ty_enum(did
, _
) if ty
::has_dtor(bccx
.tcx
, did
) => {
144 &format
!("cannot move out of type `{}`, \
145 which defines the `Drop` trait",
146 b
.ty
.user_string(bccx
.tcx
)));
149 bccx
.span_bug(move_from
.span
, "this path should not cause illegal move")
154 bccx
.span_bug(move_from
.span
, "this path should not cause illegal move")
159 fn note_move_destination(bccx
: &BorrowckCtxt
,
160 move_to_span
: codemap
::Span
,
161 pat_ident
: &ast
::Ident
,
162 is_first_note
: bool
) {
163 let pat_name
= pprust
::ident_to_string(pat_ident
);
167 "attempting to move value to here");
170 &format
!("to prevent the move, \
171 use `ref {0}` or `ref mut {0}` to capture value by \
175 bccx
.span_note(move_to_span
,
176 &format
!("and here (use `ref {0}` or `ref mut {0}`)",