11
11
//! Computes moves.
12
12
13
13
use borrowck:: * ;
14
- use borrowck:: gather_loans:: move_error:: MoveSpanAndPath ;
14
+ use borrowck:: gather_loans:: move_error:: MovePlace ;
15
15
use borrowck:: gather_loans:: move_error:: { MoveError , MoveErrorCollector } ;
16
16
use borrowck:: move_data:: * ;
17
17
use rustc:: middle:: expr_use_visitor as euv;
@@ -23,13 +23,67 @@ use rustc::ty::{self, Ty};
23
23
use std:: rc:: Rc ;
24
24
use syntax:: ast;
25
25
use syntax_pos:: Span ;
26
- use rustc:: hir:: { self , PatKind } ;
26
+ use rustc:: hir:: * ;
27
+ use rustc:: hir:: map:: Node :: * ;
27
28
28
29
struct GatherMoveInfo < ' tcx > {
29
30
id : ast:: NodeId ,
30
31
kind : MoveKind ,
31
32
cmt : mc:: cmt < ' tcx > ,
32
- span_path_opt : Option < MoveSpanAndPath >
33
+ span_path_opt : Option < MovePlace < ' tcx > >
34
+ }
35
+
36
+ /// Represents the kind of pattern
37
+ #[ derive( Debug , Clone , Copy ) ]
38
+ pub enum PatternSource < ' tcx > {
39
+ MatchExpr ( & ' tcx Expr ) ,
40
+ LetDecl ( & ' tcx Local ) ,
41
+ Other ,
42
+ }
43
+
44
+ /// Analyzes the context where the pattern appears to determine the
45
+ /// kind of hint we want to give. In particular, if the pattern is in a `match`
46
+ /// or nested within other patterns, we want to suggest a `ref` binding:
47
+ ///
48
+ /// let (a, b) = v[0]; // like the `a` and `b` patterns here
49
+ /// match v[0] { a => ... } // or the `a` pattern here
50
+ ///
51
+ /// But if the pattern is the outermost pattern in a `let`, we would rather
52
+ /// suggest that the author add a `&` to the initializer:
53
+ ///
54
+ /// let x = v[0]; // suggest `&v[0]` here
55
+ ///
56
+ /// In this latter case, this function will return `PatternSource::LetDecl`
57
+ /// with a reference to the let
58
+ fn get_pattern_source < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , pat : & Pat ) -> PatternSource < ' tcx > {
59
+
60
+ let parent = tcx. hir . get_parent_node ( pat. id ) ;
61
+
62
+ match tcx. hir . get ( parent) {
63
+ NodeExpr ( ref e) => {
64
+ // the enclosing expression must be a `match` or something else
65
+ assert ! ( match e. node {
66
+ ExprMatch ( ..) => true ,
67
+ _ => return PatternSource :: Other ,
68
+ } ) ;
69
+ PatternSource :: MatchExpr ( e)
70
+ }
71
+ NodeStmt ( ref s) => {
72
+ // the enclosing statement must be a `let` or something else
73
+ match s. node {
74
+ StmtDecl ( ref decl, _) => {
75
+ match decl. node {
76
+ DeclLocal ( ref local) => PatternSource :: LetDecl ( local) ,
77
+ _ => return PatternSource :: Other ,
78
+ }
79
+ }
80
+ _ => return PatternSource :: Other ,
81
+ }
82
+ }
83
+
84
+ _ => return PatternSource :: Other ,
85
+
86
+ }
33
87
}
34
88
35
89
pub fn gather_decl < ' a , ' tcx > ( bccx : & BorrowckCtxt < ' a , ' tcx > ,
@@ -95,11 +149,15 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
95
149
move_error_collector : & mut MoveErrorCollector < ' tcx > ,
96
150
move_pat : & hir:: Pat ,
97
151
cmt : mc:: cmt < ' tcx > ) {
152
+ let source = get_pattern_source ( bccx. tcx , move_pat) ;
98
153
let pat_span_path_opt = match move_pat. node {
99
154
PatKind :: Binding ( _, _, ref path1, _) => {
100
- Some ( MoveSpanAndPath { span : move_pat. span ,
101
- name : path1. node } )
102
- } ,
155
+ Some ( MovePlace {
156
+ span : move_pat. span ,
157
+ name : path1. node ,
158
+ pat_source : source,
159
+ } )
160
+ }
103
161
_ => None ,
104
162
} ;
105
163
let move_info = GatherMoveInfo {
@@ -108,6 +166,11 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
108
166
cmt : cmt,
109
167
span_path_opt : pat_span_path_opt,
110
168
} ;
169
+
170
+ debug ! ( "gather_move_from_pat: move_pat={:?} source={:?}" ,
171
+ move_pat,
172
+ source) ;
173
+
111
174
gather_move ( bccx, move_data, move_error_collector, move_info) ;
112
175
}
113
176
0 commit comments