1
1
import syntax:: print:: pprust;
2
+ import syntax:: ast_util:: { walk_pat} ;
3
+ import pat_util :: { pat_is_variant} ;
2
4
3
5
fn check_alt ( fcx : @fn_ctxt ,
4
6
expr : @ast:: expr ,
@@ -18,17 +20,16 @@ fn check_alt(fcx: @fn_ctxt,
18
20
fcx: fcx,
19
21
map: pat_id_map ( tcx. def_map , arm. pats [ 0 ] ) ,
20
22
alt_region: ty:: re_scope ( expr. id ) ,
21
- block_region: ty:: re_scope ( arm. body . node . id ) ,
22
- pat_region: ty:: re_scope ( expr. id ) ,
23
- // The following three fields determine whether 'move' is allowed.
24
- matching_lvalue: is_lvalue,
25
- has_guard: arm. guard . is_some ( ) ,
26
- // Each arm is freshly allowed to decide whether it can 'move'.
27
- mut ever_bound_by_ref: false ,
23
+ block_region: ty:: re_scope ( arm. body . node . id )
28
24
} ;
29
25
30
26
for arm. pats. each |p| { check_pat( pcx, p, pattern_ty) ; }
27
+ check_legality_of_move_bindings( fcx,
28
+ is_lvalue,
29
+ arm. guard. is_some( ) ,
30
+ arm. pats) ;
31
31
}
32
+
32
33
// Now typecheck the blocks.
33
34
let mut result_ty = fcx. infcx . next_ty_var ( ) ;
34
35
let mut arm_non_bot = false ;
@@ -47,20 +48,72 @@ fn check_alt(fcx: @fn_ctxt,
47
48
return bot;
48
49
}
49
50
51
+ fn check_legality_of_move_bindings ( fcx : @fn_ctxt ,
52
+ is_lvalue : bool ,
53
+ has_guard : bool ,
54
+ pats : & [ @ast:: pat ] )
55
+ {
56
+ let tcx = fcx. tcx ( ) ;
57
+ let def_map = tcx. def_map ;
58
+ let mut by_ref = None ;
59
+ let mut any_by_move = false ;
60
+ for pats. each |pat| {
61
+ do pat_util:: pat_bindings( def_map, pat) |bm, _id, span, _path| {
62
+ match bm {
63
+ ast:: bind_by_ref( _) | ast:: bind_by_implicit_ref => {
64
+ by_ref = Some ( span) ;
65
+ }
66
+ ast:: bind_by_move => {
67
+ any_by_move = true ;
68
+ }
69
+ _ => { }
70
+ }
71
+ }
72
+ }
73
+
74
+ if !any_by_move { return ; } // pointless micro-optimization
75
+ for pats. each |pat| {
76
+ do walk_pat( pat) |p| {
77
+ if !pat_is_variant ( def_map, p) {
78
+ match p. node {
79
+ ast:: pat_ident( ast:: bind_by_move, _, sub) => {
80
+ // check legality of moving out of the enum
81
+ if sub. is_some ( ) {
82
+ tcx. sess . span_err (
83
+ p. span ,
84
+ ~"cannot bind by-move with sub-bindings") ;
85
+ } else if has_guard {
86
+ tcx. sess . span_err (
87
+ p. span ,
88
+ ~"cannot bind by-move into a pattern guard") ;
89
+ } else if by_ref. is_some ( ) {
90
+ tcx. sess . span_err (
91
+ p. span ,
92
+ ~"cannot bind by-move and by-ref \
93
+ in the same pattern") ;
94
+ tcx. sess . span_note (
95
+ by_ref. get ( ) ,
96
+ ~"by-ref binding occurs here") ;
97
+ } else if is_lvalue {
98
+ tcx. sess . span_err (
99
+ p. span ,
100
+ ~"cannot bind by-move when \
101
+ matching an lvalue") ;
102
+ }
103
+ }
104
+ _ => { }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+
111
+
50
112
type pat_ctxt = {
51
113
fcx: @fn_ctxt,
52
114
map: pat_id_map,
53
- alt_region: ty:: region,
54
- block_region: ty:: region,
55
- /* Equal to either alt_region or block_region. */
56
- pat_region: ty:: region,
57
- /* Moving out is only permitted when matching rvalues. */
58
- matching_lvalue: bool ,
59
- /* Moving out is not permitted with guards. */
60
- has_guard: bool ,
61
- /* If a pattern binding binds by-reference ever, then binding by-move in
62
- * the same arm is disallowed (no "ref x @ some(move y)", etc etc). */
63
- mut ever_bound_by_ref: bool,
115
+ alt_region: ty:: region, // Region for the alt as a whole
116
+ block_region: ty:: region, // Region for the block of the arm
64
117
} ;
65
118
66
119
fn check_pat_variant( pcx : pat_ctxt , pat : @ast:: pat , path : @ast:: path ,
@@ -174,7 +227,6 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
174
227
175
228
match bm {
176
229
ast::bind_by_ref(mutbl) => {
177
- pcx.ever_bound_by_ref = true;
178
230
// if the binding is like
179
231
// ref x | ref const x | ref mut x
180
232
// then the type of x is &M T where M is the mutability
@@ -192,26 +244,8 @@ fn check_pat(pcx: pat_ctxt, pat: @ast::pat, expected: ty::t) {
192
244
}
193
245
ast::bind_by_move => {
194
246
demand::eqtype(fcx, pat.span, expected, typ);
195
- // check legality of moving out of the enum
196
- if sub.is_some() {
197
- tcx.sess.span_err(pat.span,
198
- ~" cannot bind by-move with sub-bindings");
199
- }
200
- if pcx.has_guard {
201
- tcx.sess.span_err(pat.span,
202
- ~" cannot bind by-move into a pattern guard");
203
- }
204
- if pcx.ever_bound_by_ref {
205
- tcx.sess.span_err(pat.span,
206
- ~" cannot bind by-move and by-ref in the same pattern");
207
- }
208
- if pcx.matching_lvalue {
209
- tcx.sess.span_err(pat.span,
210
- ~" cannot bind by-move when matching an lvalue");
211
- }
212
247
}
213
248
ast::bind_by_implicit_ref => {
214
- pcx.ever_bound_by_ref = true;
215
249
demand::eqtype(fcx, pat.span, expected, typ);
216
250
}
217
251
}
0 commit comments