]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | //! A different sort of visitor for walking fn bodies. Unlike the | |
12 | //! normal visitor, which just walks the entire body in one shot, the | |
13 | //! `ExprUseVisitor` determines how expressions are being used. | |
14 | ||
1a4d82fc JJ |
15 | pub use self::LoanCause::*; |
16 | pub use self::ConsumeMode::*; | |
17 | pub use self::MoveReason::*; | |
18 | pub use self::MatchMode::*; | |
19 | use self::TrackMatchMode::*; | |
20 | use self::OverloadedCallType::*; | |
21 | ||
54a0048b SL |
22 | use hir::pat_util; |
23 | use hir::def::Def; | |
24 | use hir::def_id::{DefId}; | |
25 | use infer; | |
1a4d82fc | 26 | use middle::mem_categorization as mc; |
54a0048b | 27 | use ty::{self, TyCtxt, adjustment}; |
1a4d82fc | 28 | |
54a0048b | 29 | use hir::{self, PatKind}; |
e9174d1e SL |
30 | |
31 | use syntax::ast; | |
1a4d82fc JJ |
32 | use syntax::ptr::P; |
33 | use syntax::codemap::Span; | |
34 | ||
35 | /////////////////////////////////////////////////////////////////////////// | |
36 | // The Delegate trait | |
37 | ||
38 | /// This trait defines the callbacks you can expect to receive when | |
39 | /// employing the ExprUseVisitor. | |
40 | pub trait Delegate<'tcx> { | |
41 | // The value found at `cmt` is either copied or moved, depending | |
42 | // on mode. | |
43 | fn consume(&mut self, | |
44 | consume_id: ast::NodeId, | |
45 | consume_span: Span, | |
46 | cmt: mc::cmt<'tcx>, | |
47 | mode: ConsumeMode); | |
48 | ||
49 | // The value found at `cmt` has been determined to match the | |
50 | // pattern binding `matched_pat`, and its subparts are being | |
51 | // copied or moved depending on `mode`. Note that `matched_pat` | |
52 | // is called on all variant/structs in the pattern (i.e., the | |
53 | // interior nodes of the pattern's tree structure) while | |
54 | // consume_pat is called on the binding identifiers in the pattern | |
55 | // (which are leaves of the pattern's tree structure). | |
56 | // | |
57 | // Note that variants/structs and identifiers are disjoint; thus | |
58 | // `matched_pat` and `consume_pat` are never both called on the | |
59 | // same input pattern structure (though of `consume_pat` can be | |
60 | // called on a subpart of an input passed to `matched_pat). | |
61 | fn matched_pat(&mut self, | |
e9174d1e | 62 | matched_pat: &hir::Pat, |
1a4d82fc JJ |
63 | cmt: mc::cmt<'tcx>, |
64 | mode: MatchMode); | |
65 | ||
66 | // The value found at `cmt` is either copied or moved via the | |
67 | // pattern binding `consume_pat`, depending on mode. | |
68 | fn consume_pat(&mut self, | |
e9174d1e | 69 | consume_pat: &hir::Pat, |
1a4d82fc JJ |
70 | cmt: mc::cmt<'tcx>, |
71 | mode: ConsumeMode); | |
72 | ||
73 | // The value found at `borrow` is being borrowed at the point | |
74 | // `borrow_id` for the region `loan_region` with kind `bk`. | |
75 | fn borrow(&mut self, | |
76 | borrow_id: ast::NodeId, | |
77 | borrow_span: Span, | |
78 | cmt: mc::cmt<'tcx>, | |
79 | loan_region: ty::Region, | |
80 | bk: ty::BorrowKind, | |
81 | loan_cause: LoanCause); | |
82 | ||
83 | // The local variable `id` is declared but not initialized. | |
84 | fn decl_without_init(&mut self, | |
85 | id: ast::NodeId, | |
86 | span: Span); | |
87 | ||
88 | // The path at `cmt` is being assigned to. | |
89 | fn mutate(&mut self, | |
90 | assignment_id: ast::NodeId, | |
91 | assignment_span: Span, | |
92 | assignee_cmt: mc::cmt<'tcx>, | |
93 | mode: MutateMode); | |
94 | } | |
95 | ||
c34b1796 | 96 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
97 | pub enum LoanCause { |
98 | ClosureCapture(Span), | |
99 | AddrOf, | |
100 | AutoRef, | |
9346a6ac | 101 | AutoUnsafe, |
1a4d82fc JJ |
102 | RefBinding, |
103 | OverloadedOperator, | |
104 | ClosureInvocation, | |
105 | ForLoop, | |
106 | MatchDiscriminant | |
107 | } | |
108 | ||
c34b1796 | 109 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
110 | pub enum ConsumeMode { |
111 | Copy, // reference to x where x has a type that copies | |
112 | Move(MoveReason), // reference to x where x has a type that moves | |
113 | } | |
114 | ||
c34b1796 | 115 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
116 | pub enum MoveReason { |
117 | DirectRefMove, | |
118 | PatBindingMove, | |
119 | CaptureMove, | |
120 | } | |
121 | ||
c34b1796 | 122 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
123 | pub enum MatchMode { |
124 | NonBindingMatch, | |
125 | BorrowingMatch, | |
126 | CopyingMatch, | |
127 | MovingMatch, | |
128 | } | |
129 | ||
c34b1796 | 130 | #[derive(Copy, Clone, PartialEq, Debug)] |
85aaf69f | 131 | enum TrackMatchMode { |
1a4d82fc JJ |
132 | Unknown, |
133 | Definite(MatchMode), | |
134 | Conflicting, | |
135 | } | |
136 | ||
85aaf69f | 137 | impl TrackMatchMode { |
1a4d82fc JJ |
138 | // Builds up the whole match mode for a pattern from its constituent |
139 | // parts. The lattice looks like this: | |
140 | // | |
141 | // Conflicting | |
142 | // / \ | |
143 | // / \ | |
144 | // Borrowing Moving | |
145 | // \ / | |
146 | // \ / | |
147 | // Copying | |
148 | // | | |
149 | // NonBinding | |
150 | // | | |
151 | // Unknown | |
152 | // | |
153 | // examples: | |
154 | // | |
155 | // * `(_, some_int)` pattern is Copying, since | |
156 | // NonBinding + Copying => Copying | |
157 | // | |
158 | // * `(some_int, some_box)` pattern is Moving, since | |
159 | // Copying + Moving => Moving | |
160 | // | |
161 | // * `(ref x, some_box)` pattern is Conflicting, since | |
162 | // Borrowing + Moving => Conflicting | |
163 | // | |
164 | // Note that the `Unknown` and `Conflicting` states are | |
165 | // represented separately from the other more interesting | |
166 | // `Definite` states, which simplifies logic here somewhat. | |
167 | fn lub(&mut self, mode: MatchMode) { | |
168 | *self = match (*self, mode) { | |
169 | // Note that clause order below is very significant. | |
170 | (Unknown, new) => Definite(new), | |
171 | (Definite(old), new) if old == new => Definite(old), | |
172 | ||
173 | (Definite(old), NonBindingMatch) => Definite(old), | |
174 | (Definite(NonBindingMatch), new) => Definite(new), | |
175 | ||
176 | (Definite(old), CopyingMatch) => Definite(old), | |
177 | (Definite(CopyingMatch), new) => Definite(new), | |
178 | ||
179 | (Definite(_), _) => Conflicting, | |
180 | (Conflicting, _) => *self, | |
181 | }; | |
182 | } | |
183 | ||
184 | fn match_mode(&self) -> MatchMode { | |
185 | match *self { | |
186 | Unknown => NonBindingMatch, | |
187 | Definite(mode) => mode, | |
188 | Conflicting => { | |
189 | // Conservatively return MovingMatch to let the | |
190 | // compiler continue to make progress. | |
191 | MovingMatch | |
192 | } | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
c34b1796 | 197 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
198 | pub enum MutateMode { |
199 | Init, | |
200 | JustWrite, // x = y | |
201 | WriteAndRead, // x += y | |
202 | } | |
203 | ||
c34b1796 | 204 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
205 | enum OverloadedCallType { |
206 | FnOverloadedCall, | |
207 | FnMutOverloadedCall, | |
208 | FnOnceOverloadedCall, | |
209 | } | |
210 | ||
211 | impl OverloadedCallType { | |
54a0048b | 212 | fn from_trait_id(tcx: &TyCtxt, trait_id: DefId) |
1a4d82fc | 213 | -> OverloadedCallType { |
62682a34 | 214 | for &(maybe_function_trait, overloaded_call_type) in &[ |
1a4d82fc JJ |
215 | (tcx.lang_items.fn_once_trait(), FnOnceOverloadedCall), |
216 | (tcx.lang_items.fn_mut_trait(), FnMutOverloadedCall), | |
217 | (tcx.lang_items.fn_trait(), FnOverloadedCall) | |
62682a34 | 218 | ] { |
1a4d82fc JJ |
219 | match maybe_function_trait { |
220 | Some(function_trait) if function_trait == trait_id => { | |
221 | return overloaded_call_type | |
222 | } | |
223 | _ => continue, | |
224 | } | |
225 | } | |
226 | ||
54a0048b | 227 | bug!("overloaded call didn't map to known function trait") |
1a4d82fc JJ |
228 | } |
229 | ||
54a0048b | 230 | fn from_method_id(tcx: &TyCtxt, method_id: DefId) |
1a4d82fc | 231 | -> OverloadedCallType { |
c1a9b12d SL |
232 | let method = tcx.impl_or_trait_item(method_id); |
233 | OverloadedCallType::from_trait_id(tcx, method.container().id()) | |
1a4d82fc JJ |
234 | } |
235 | } | |
236 | ||
237 | /////////////////////////////////////////////////////////////////////////// | |
238 | // The ExprUseVisitor type | |
239 | // | |
240 | // This is the code that actually walks the tree. Like | |
241 | // mem_categorization, it requires a TYPER, which is a type that | |
242 | // supplies types from the tree. After type checking is complete, you | |
243 | // can just use the tcx as the typer. | |
b039eaaf | 244 | pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> { |
c1a9b12d SL |
245 | typer: &'t infer::InferCtxt<'a, 'tcx>, |
246 | mc: mc::MemCategorizationContext<'t, 'a, 'tcx>, | |
e9174d1e | 247 | delegate: &'d mut Delegate<'tcx>, |
1a4d82fc JJ |
248 | } |
249 | ||
250 | // If the TYPER results in an error, it's because the type check | |
251 | // failed (or will fail, when the error is uncovered and reported | |
252 | // during writeback). In this case, we just ignore this part of the | |
253 | // code. | |
254 | // | |
255 | // Note that this macro appears similar to try!(), but, unlike try!(), | |
256 | // it does not propagate the error. | |
257 | macro_rules! return_if_err { | |
258 | ($inp: expr) => ( | |
259 | match $inp { | |
260 | Ok(v) => v, | |
c1a9b12d SL |
261 | Err(()) => { |
262 | debug!("mc reported err"); | |
263 | return | |
264 | } | |
1a4d82fc JJ |
265 | } |
266 | ) | |
267 | } | |
268 | ||
269 | /// Whether the elements of an overloaded operation are passed by value or by reference | |
270 | enum PassArgs { | |
271 | ByValue, | |
272 | ByRef, | |
273 | } | |
274 | ||
c1a9b12d | 275 | impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { |
9cc50fc6 | 276 | pub fn new(delegate: &'d mut (Delegate<'tcx>+'d), |
c1a9b12d | 277 | typer: &'t infer::InferCtxt<'a, 'tcx>) |
b039eaaf | 278 | -> ExprUseVisitor<'d,'t,'a,'tcx> where 'tcx:'a+'d |
e9174d1e | 279 | { |
b039eaaf SL |
280 | let mc: mc::MemCategorizationContext<'t, 'a, 'tcx> = |
281 | mc::MemCategorizationContext::new(typer); | |
282 | ExprUseVisitor { typer: typer, mc: mc, delegate: delegate } | |
1a4d82fc JJ |
283 | } |
284 | ||
285 | pub fn walk_fn(&mut self, | |
e9174d1e SL |
286 | decl: &hir::FnDecl, |
287 | body: &hir::Block) { | |
1a4d82fc JJ |
288 | self.walk_arg_patterns(decl, body); |
289 | self.walk_block(body); | |
290 | } | |
291 | ||
292 | fn walk_arg_patterns(&mut self, | |
e9174d1e SL |
293 | decl: &hir::FnDecl, |
294 | body: &hir::Block) { | |
85aaf69f | 295 | for arg in &decl.inputs { |
1a4d82fc JJ |
296 | let arg_ty = return_if_err!(self.typer.node_ty(arg.pat.id)); |
297 | ||
e9174d1e | 298 | let fn_body_scope = self.tcx().region_maps.node_extent(body.id); |
1a4d82fc JJ |
299 | let arg_cmt = self.mc.cat_rvalue( |
300 | arg.id, | |
301 | arg.pat.span, | |
302 | ty::ReScope(fn_body_scope), // Args live only as long as the fn body. | |
303 | arg_ty); | |
304 | ||
7453a54e | 305 | self.walk_irrefutable_pat(arg_cmt, &arg.pat); |
1a4d82fc JJ |
306 | } |
307 | } | |
308 | ||
54a0048b | 309 | fn tcx(&self) -> &'t TyCtxt<'tcx> { |
c1a9b12d | 310 | self.typer.tcx |
1a4d82fc JJ |
311 | } |
312 | ||
313 | fn delegate_consume(&mut self, | |
314 | consume_id: ast::NodeId, | |
315 | consume_span: Span, | |
316 | cmt: mc::cmt<'tcx>) { | |
62682a34 SL |
317 | debug!("delegate_consume(consume_id={}, cmt={:?})", |
318 | consume_id, cmt); | |
85aaf69f | 319 | |
1a4d82fc JJ |
320 | let mode = copy_or_move(self.typer, &cmt, DirectRefMove); |
321 | self.delegate.consume(consume_id, consume_span, cmt, mode); | |
322 | } | |
323 | ||
9cc50fc6 | 324 | fn consume_exprs(&mut self, exprs: &[P<hir::Expr>]) { |
85aaf69f | 325 | for expr in exprs { |
7453a54e | 326 | self.consume_expr(&expr); |
1a4d82fc JJ |
327 | } |
328 | } | |
329 | ||
e9174d1e | 330 | pub fn consume_expr(&mut self, expr: &hir::Expr) { |
62682a34 | 331 | debug!("consume_expr(expr={:?})", expr); |
1a4d82fc JJ |
332 | |
333 | let cmt = return_if_err!(self.mc.cat_expr(expr)); | |
334 | self.delegate_consume(expr.id, expr.span, cmt); | |
335 | self.walk_expr(expr); | |
336 | } | |
337 | ||
338 | fn mutate_expr(&mut self, | |
e9174d1e SL |
339 | assignment_expr: &hir::Expr, |
340 | expr: &hir::Expr, | |
1a4d82fc JJ |
341 | mode: MutateMode) { |
342 | let cmt = return_if_err!(self.mc.cat_expr(expr)); | |
343 | self.delegate.mutate(assignment_expr.id, assignment_expr.span, cmt, mode); | |
344 | self.walk_expr(expr); | |
345 | } | |
346 | ||
347 | fn borrow_expr(&mut self, | |
e9174d1e | 348 | expr: &hir::Expr, |
1a4d82fc JJ |
349 | r: ty::Region, |
350 | bk: ty::BorrowKind, | |
351 | cause: LoanCause) { | |
62682a34 SL |
352 | debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})", |
353 | expr, r, bk); | |
1a4d82fc JJ |
354 | |
355 | let cmt = return_if_err!(self.mc.cat_expr(expr)); | |
356 | self.delegate.borrow(expr.id, expr.span, cmt, r, bk, cause); | |
357 | ||
1a4d82fc JJ |
358 | self.walk_expr(expr) |
359 | } | |
360 | ||
e9174d1e | 361 | fn select_from_expr(&mut self, expr: &hir::Expr) { |
1a4d82fc JJ |
362 | self.walk_expr(expr) |
363 | } | |
364 | ||
e9174d1e | 365 | pub fn walk_expr(&mut self, expr: &hir::Expr) { |
62682a34 | 366 | debug!("walk_expr(expr={:?})", expr); |
1a4d82fc JJ |
367 | |
368 | self.walk_adjustment(expr); | |
369 | ||
370 | match expr.node { | |
e9174d1e | 371 | hir::ExprPath(..) => { } |
1a4d82fc | 372 | |
9cc50fc6 | 373 | hir::ExprType(ref subexpr, _) => { |
7453a54e | 374 | self.walk_expr(&subexpr) |
9cc50fc6 SL |
375 | } |
376 | ||
e9174d1e | 377 | hir::ExprUnary(hir::UnDeref, ref base) => { // *base |
7453a54e SL |
378 | if !self.walk_overloaded_operator(expr, &base, Vec::new(), PassArgs::ByRef) { |
379 | self.select_from_expr(&base); | |
1a4d82fc JJ |
380 | } |
381 | } | |
382 | ||
e9174d1e | 383 | hir::ExprField(ref base, _) => { // base.f |
7453a54e | 384 | self.select_from_expr(&base); |
1a4d82fc JJ |
385 | } |
386 | ||
e9174d1e | 387 | hir::ExprTupField(ref base, _) => { // base.<n> |
7453a54e | 388 | self.select_from_expr(&base); |
1a4d82fc JJ |
389 | } |
390 | ||
e9174d1e | 391 | hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] |
1a4d82fc | 392 | if !self.walk_overloaded_operator(expr, |
7453a54e SL |
393 | &lhs, |
394 | vec![&rhs], | |
c34b1796 | 395 | PassArgs::ByValue) { |
7453a54e SL |
396 | self.select_from_expr(&lhs); |
397 | self.consume_expr(&rhs); | |
1a4d82fc JJ |
398 | } |
399 | } | |
400 | ||
e9174d1e | 401 | hir::ExprCall(ref callee, ref args) => { // callee(args) |
7453a54e | 402 | self.walk_callee(expr, &callee); |
1a4d82fc JJ |
403 | self.consume_exprs(args); |
404 | } | |
405 | ||
e9174d1e | 406 | hir::ExprMethodCall(_, _, ref args) => { // callee.m(args) |
1a4d82fc JJ |
407 | self.consume_exprs(args); |
408 | } | |
409 | ||
e9174d1e | 410 | hir::ExprStruct(_, ref fields, ref opt_with) => { |
1a4d82fc JJ |
411 | self.walk_struct_expr(expr, fields, opt_with); |
412 | } | |
413 | ||
e9174d1e | 414 | hir::ExprTup(ref exprs) => { |
1a4d82fc JJ |
415 | self.consume_exprs(exprs); |
416 | } | |
417 | ||
e9174d1e | 418 | hir::ExprIf(ref cond_expr, ref then_blk, ref opt_else_expr) => { |
7453a54e SL |
419 | self.consume_expr(&cond_expr); |
420 | self.walk_block(&then_blk); | |
85aaf69f | 421 | if let Some(ref else_expr) = *opt_else_expr { |
7453a54e | 422 | self.consume_expr(&else_expr); |
1a4d82fc JJ |
423 | } |
424 | } | |
425 | ||
e9174d1e | 426 | hir::ExprMatch(ref discr, ref arms, _) => { |
7453a54e SL |
427 | let discr_cmt = return_if_err!(self.mc.cat_expr(&discr)); |
428 | self.borrow_expr(&discr, ty::ReEmpty, ty::ImmBorrow, MatchDiscriminant); | |
1a4d82fc JJ |
429 | |
430 | // treatment of the discriminant is handled while walking the arms. | |
85aaf69f | 431 | for arm in arms { |
1a4d82fc JJ |
432 | let mode = self.arm_move_mode(discr_cmt.clone(), arm); |
433 | let mode = mode.match_mode(); | |
434 | self.walk_arm(discr_cmt.clone(), arm, mode); | |
435 | } | |
436 | } | |
437 | ||
e9174d1e | 438 | hir::ExprVec(ref exprs) => { |
1a4d82fc JJ |
439 | self.consume_exprs(exprs); |
440 | } | |
441 | ||
e9174d1e | 442 | hir::ExprAddrOf(m, ref base) => { // &base |
1a4d82fc JJ |
443 | // make sure that the thing we are pointing out stays valid |
444 | // for the lifetime `scope_r` of the resulting ptr: | |
445 | let expr_ty = return_if_err!(self.typer.node_ty(expr.id)); | |
c1a9b12d SL |
446 | if let ty::TyRef(&r, _) = expr_ty.sty { |
447 | let bk = ty::BorrowKind::from_mutbl(m); | |
7453a54e | 448 | self.borrow_expr(&base, r, bk, AddrOf); |
c1a9b12d | 449 | } |
1a4d82fc JJ |
450 | } |
451 | ||
54a0048b SL |
452 | hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => { |
453 | for (o, output) in ia.outputs.iter().zip(outputs) { | |
454 | if o.is_indirect { | |
455 | self.consume_expr(output); | |
9cc50fc6 | 456 | } else { |
54a0048b SL |
457 | self.mutate_expr(expr, output, |
458 | if o.is_rw { | |
9cc50fc6 SL |
459 | MutateMode::WriteAndRead |
460 | } else { | |
461 | MutateMode::JustWrite | |
462 | }); | |
463 | } | |
1a4d82fc | 464 | } |
54a0048b | 465 | self.consume_exprs(inputs); |
1a4d82fc JJ |
466 | } |
467 | ||
e9174d1e SL |
468 | hir::ExprBreak(..) | |
469 | hir::ExprAgain(..) | | |
470 | hir::ExprLit(..) => {} | |
1a4d82fc | 471 | |
e9174d1e | 472 | hir::ExprLoop(ref blk, _) => { |
7453a54e | 473 | self.walk_block(&blk); |
1a4d82fc JJ |
474 | } |
475 | ||
e9174d1e | 476 | hir::ExprWhile(ref cond_expr, ref blk, _) => { |
7453a54e SL |
477 | self.consume_expr(&cond_expr); |
478 | self.walk_block(&blk); | |
1a4d82fc JJ |
479 | } |
480 | ||
e9174d1e | 481 | hir::ExprUnary(op, ref lhs) => { |
54a0048b | 482 | let pass_args = if op.is_by_value() { |
1a4d82fc JJ |
483 | PassArgs::ByValue |
484 | } else { | |
485 | PassArgs::ByRef | |
486 | }; | |
487 | ||
7453a54e SL |
488 | if !self.walk_overloaded_operator(expr, &lhs, Vec::new(), pass_args) { |
489 | self.consume_expr(&lhs); | |
1a4d82fc JJ |
490 | } |
491 | } | |
492 | ||
e9174d1e | 493 | hir::ExprBinary(op, ref lhs, ref rhs) => { |
54a0048b | 494 | let pass_args = if op.node.is_by_value() { |
1a4d82fc JJ |
495 | PassArgs::ByValue |
496 | } else { | |
497 | PassArgs::ByRef | |
498 | }; | |
499 | ||
7453a54e SL |
500 | if !self.walk_overloaded_operator(expr, &lhs, vec![&rhs], pass_args) { |
501 | self.consume_expr(&lhs); | |
502 | self.consume_expr(&rhs); | |
1a4d82fc JJ |
503 | } |
504 | } | |
505 | ||
e9174d1e | 506 | hir::ExprBlock(ref blk) => { |
7453a54e | 507 | self.walk_block(&blk); |
1a4d82fc JJ |
508 | } |
509 | ||
e9174d1e | 510 | hir::ExprRet(ref opt_expr) => { |
85aaf69f | 511 | if let Some(ref expr) = *opt_expr { |
7453a54e | 512 | self.consume_expr(&expr); |
1a4d82fc JJ |
513 | } |
514 | } | |
515 | ||
e9174d1e | 516 | hir::ExprAssign(ref lhs, ref rhs) => { |
7453a54e SL |
517 | self.mutate_expr(expr, &lhs, MutateMode::JustWrite); |
518 | self.consume_expr(&rhs); | |
1a4d82fc JJ |
519 | } |
520 | ||
e9174d1e | 521 | hir::ExprCast(ref base, _) => { |
7453a54e | 522 | self.consume_expr(&base); |
1a4d82fc JJ |
523 | } |
524 | ||
b039eaaf SL |
525 | hir::ExprAssignOp(op, ref lhs, ref rhs) => { |
526 | // NB All our assignment operations take the RHS by value | |
54a0048b | 527 | assert!(op.node.is_by_value()); |
b039eaaf SL |
528 | |
529 | if !self.walk_overloaded_operator(expr, lhs, vec![rhs], PassArgs::ByValue) { | |
7453a54e SL |
530 | self.mutate_expr(expr, &lhs, MutateMode::WriteAndRead); |
531 | self.consume_expr(&rhs); | |
b039eaaf | 532 | } |
1a4d82fc JJ |
533 | } |
534 | ||
e9174d1e | 535 | hir::ExprRepeat(ref base, ref count) => { |
7453a54e SL |
536 | self.consume_expr(&base); |
537 | self.consume_expr(&count); | |
1a4d82fc JJ |
538 | } |
539 | ||
e9174d1e | 540 | hir::ExprClosure(..) => { |
1a4d82fc JJ |
541 | self.walk_captures(expr) |
542 | } | |
543 | ||
b039eaaf | 544 | hir::ExprBox(ref base) => { |
7453a54e | 545 | self.consume_expr(&base); |
1a4d82fc | 546 | } |
1a4d82fc JJ |
547 | } |
548 | } | |
549 | ||
e9174d1e | 550 | fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) { |
1a4d82fc | 551 | let callee_ty = return_if_err!(self.typer.expr_ty_adjusted(callee)); |
62682a34 SL |
552 | debug!("walk_callee: callee={:?} callee_ty={:?}", |
553 | callee, callee_ty); | |
e9174d1e | 554 | let call_scope = self.tcx().region_maps.node_extent(call.id); |
1a4d82fc | 555 | match callee_ty.sty { |
54a0048b | 556 | ty::TyFnDef(..) | ty::TyFnPtr(_) => { |
1a4d82fc JJ |
557 | self.consume_expr(callee); |
558 | } | |
62682a34 | 559 | ty::TyError => { } |
1a4d82fc JJ |
560 | _ => { |
561 | let overloaded_call_type = | |
c1a9b12d SL |
562 | match self.typer.node_method_id(ty::MethodCall::expr(call.id)) { |
563 | Some(method_id) => { | |
564 | OverloadedCallType::from_method_id(self.tcx(), method_id) | |
1a4d82fc JJ |
565 | } |
566 | None => { | |
54a0048b | 567 | span_bug!( |
1a4d82fc | 568 | callee.span, |
54a0048b SL |
569 | "unexpected callee type {}", |
570 | callee_ty) | |
1a4d82fc JJ |
571 | } |
572 | }; | |
573 | match overloaded_call_type { | |
574 | FnMutOverloadedCall => { | |
575 | self.borrow_expr(callee, | |
576 | ty::ReScope(call_scope), | |
577 | ty::MutBorrow, | |
578 | ClosureInvocation); | |
579 | } | |
580 | FnOverloadedCall => { | |
581 | self.borrow_expr(callee, | |
582 | ty::ReScope(call_scope), | |
583 | ty::ImmBorrow, | |
584 | ClosureInvocation); | |
585 | } | |
586 | FnOnceOverloadedCall => self.consume_expr(callee), | |
587 | } | |
588 | } | |
589 | } | |
590 | } | |
591 | ||
e9174d1e | 592 | fn walk_stmt(&mut self, stmt: &hir::Stmt) { |
1a4d82fc | 593 | match stmt.node { |
e9174d1e | 594 | hir::StmtDecl(ref decl, _) => { |
1a4d82fc | 595 | match decl.node { |
e9174d1e | 596 | hir::DeclLocal(ref local) => { |
7453a54e | 597 | self.walk_local(&local); |
1a4d82fc JJ |
598 | } |
599 | ||
e9174d1e | 600 | hir::DeclItem(_) => { |
1a4d82fc JJ |
601 | // we don't visit nested items in this visitor, |
602 | // only the fn body we were given. | |
603 | } | |
604 | } | |
605 | } | |
606 | ||
e9174d1e SL |
607 | hir::StmtExpr(ref expr, _) | |
608 | hir::StmtSemi(ref expr, _) => { | |
7453a54e | 609 | self.consume_expr(&expr); |
1a4d82fc | 610 | } |
1a4d82fc JJ |
611 | } |
612 | } | |
613 | ||
e9174d1e | 614 | fn walk_local(&mut self, local: &hir::Local) { |
1a4d82fc JJ |
615 | match local.init { |
616 | None => { | |
617 | let delegate = &mut self.delegate; | |
7453a54e | 618 | pat_util::pat_bindings(&self.typer.tcx.def_map, &local.pat, |
1a4d82fc JJ |
619 | |_, id, span, _| { |
620 | delegate.decl_without_init(id, span); | |
621 | }) | |
622 | } | |
623 | ||
624 | Some(ref expr) => { | |
625 | // Variable declarations with | |
626 | // initializers are considered | |
627 | // "assigns", which is handled by | |
628 | // `walk_pat`: | |
7453a54e SL |
629 | self.walk_expr(&expr); |
630 | let init_cmt = return_if_err!(self.mc.cat_expr(&expr)); | |
631 | self.walk_irrefutable_pat(init_cmt, &local.pat); | |
1a4d82fc JJ |
632 | } |
633 | } | |
634 | } | |
635 | ||
636 | /// Indicates that the value of `blk` will be consumed, meaning either copied or moved | |
637 | /// depending on its type. | |
e9174d1e | 638 | fn walk_block(&mut self, blk: &hir::Block) { |
1a4d82fc JJ |
639 | debug!("walk_block(blk.id={})", blk.id); |
640 | ||
85aaf69f | 641 | for stmt in &blk.stmts { |
92a42be0 | 642 | self.walk_stmt(stmt); |
1a4d82fc JJ |
643 | } |
644 | ||
85aaf69f | 645 | if let Some(ref tail_expr) = blk.expr { |
7453a54e | 646 | self.consume_expr(&tail_expr); |
1a4d82fc JJ |
647 | } |
648 | } | |
649 | ||
650 | fn walk_struct_expr(&mut self, | |
e9174d1e | 651 | _expr: &hir::Expr, |
9cc50fc6 | 652 | fields: &[hir::Field], |
e9174d1e | 653 | opt_with: &Option<P<hir::Expr>>) { |
1a4d82fc | 654 | // Consume the expressions supplying values for each field. |
85aaf69f | 655 | for field in fields { |
7453a54e | 656 | self.consume_expr(&field.expr); |
1a4d82fc JJ |
657 | } |
658 | ||
659 | let with_expr = match *opt_with { | |
660 | Some(ref w) => &**w, | |
661 | None => { return; } | |
662 | }; | |
663 | ||
7453a54e | 664 | let with_cmt = return_if_err!(self.mc.cat_expr(&with_expr)); |
1a4d82fc JJ |
665 | |
666 | // Select just those fields of the `with` | |
667 | // expression that will actually be used | |
e9174d1e SL |
668 | if let ty::TyStruct(def, substs) = with_cmt.ty.sty { |
669 | // Consume those fields of the with expression that are needed. | |
670 | for with_field in &def.struct_variant().fields { | |
671 | if !contains_field_named(with_field, fields) { | |
672 | let cmt_field = self.mc.cat_field( | |
673 | &*with_expr, | |
674 | with_cmt.clone(), | |
675 | with_field.name, | |
676 | with_field.ty(self.tcx(), substs) | |
677 | ); | |
678 | self.delegate_consume(with_expr.id, with_expr.span, cmt_field); | |
1a4d82fc | 679 | } |
1a4d82fc | 680 | } |
e9174d1e SL |
681 | } else { |
682 | // the base expression should always evaluate to a | |
683 | // struct; however, when EUV is run during typeck, it | |
684 | // may not. This will generate an error earlier in typeck, | |
685 | // so we can just ignore it. | |
686 | if !self.tcx().sess.has_errors() { | |
54a0048b | 687 | span_bug!( |
e9174d1e SL |
688 | with_expr.span, |
689 | "with expression doesn't evaluate to a struct"); | |
1a4d82fc | 690 | } |
e9174d1e | 691 | }; |
1a4d82fc JJ |
692 | |
693 | // walk the with expression so that complex expressions | |
694 | // are properly handled. | |
695 | self.walk_expr(with_expr); | |
696 | ||
e9174d1e | 697 | fn contains_field_named(field: ty::FieldDef, |
9cc50fc6 | 698 | fields: &[hir::Field]) |
1a4d82fc JJ |
699 | -> bool |
700 | { | |
701 | fields.iter().any( | |
b039eaaf | 702 | |f| f.name.node == field.name) |
1a4d82fc JJ |
703 | } |
704 | } | |
705 | ||
706 | // Invoke the appropriate delegate calls for anything that gets | |
707 | // consumed or borrowed as part of the automatic adjustment | |
708 | // process. | |
e9174d1e | 709 | fn walk_adjustment(&mut self, expr: &hir::Expr) { |
1a4d82fc | 710 | let typer = self.typer; |
c1a9b12d SL |
711 | //NOTE(@jroesch): mixed RefCell borrow causes crash |
712 | let adj = typer.adjustments().get(&expr.id).map(|x| x.clone()); | |
713 | if let Some(adjustment) = adj { | |
714 | match adjustment { | |
e9174d1e | 715 | adjustment::AdjustReifyFnPointer | |
7453a54e SL |
716 | adjustment::AdjustUnsafeFnPointer | |
717 | adjustment::AdjustMutToConstPointer => { | |
9346a6ac AL |
718 | // Creating a closure/fn-pointer or unsizing consumes |
719 | // the input and stores it into the resulting rvalue. | |
7453a54e | 720 | debug!("walk_adjustment: trivial adjustment"); |
9346a6ac AL |
721 | let cmt_unadjusted = |
722 | return_if_err!(self.mc.cat_expr_unadjusted(expr)); | |
723 | self.delegate_consume(expr.id, expr.span, cmt_unadjusted); | |
724 | } | |
e9174d1e | 725 | adjustment::AdjustDerefRef(ref adj) => { |
9346a6ac | 726 | self.walk_autoderefref(expr, adj); |
1a4d82fc JJ |
727 | } |
728 | } | |
729 | } | |
730 | } | |
731 | ||
732 | /// Autoderefs for overloaded Deref calls in fact reference their receiver. That is, if we have | |
733 | /// `(*x)` where `x` is of type `Rc<T>`, then this in fact is equivalent to `x.deref()`. Since | |
734 | /// `deref()` is declared with `&self`, this is an autoref of `x`. | |
735 | fn walk_autoderefs(&mut self, | |
e9174d1e | 736 | expr: &hir::Expr, |
c34b1796 | 737 | autoderefs: usize) { |
62682a34 | 738 | debug!("walk_autoderefs expr={:?} autoderefs={}", expr, autoderefs); |
1a4d82fc | 739 | |
85aaf69f | 740 | for i in 0..autoderefs { |
9346a6ac | 741 | let deref_id = ty::MethodCall::autoderef(expr.id, i as u32); |
1a4d82fc JJ |
742 | match self.typer.node_method_ty(deref_id) { |
743 | None => {} | |
744 | Some(method_ty) => { | |
745 | let cmt = return_if_err!(self.mc.cat_expr_autoderefd(expr, i)); | |
746 | ||
747 | // the method call infrastructure should have | |
748 | // replaced all late-bound regions with variables: | |
c1a9b12d SL |
749 | let self_ty = method_ty.fn_sig().input(0); |
750 | let self_ty = self.tcx().no_late_bound_regions(&self_ty).unwrap(); | |
1a4d82fc JJ |
751 | |
752 | let (m, r) = match self_ty.sty { | |
62682a34 | 753 | ty::TyRef(r, ref m) => (m.mutbl, r), |
54a0048b SL |
754 | _ => span_bug!(expr.span, |
755 | "bad overloaded deref type {:?}", | |
756 | method_ty) | |
1a4d82fc JJ |
757 | }; |
758 | let bk = ty::BorrowKind::from_mutbl(m); | |
759 | self.delegate.borrow(expr.id, expr.span, cmt, | |
760 | *r, bk, AutoRef); | |
761 | } | |
762 | } | |
763 | } | |
764 | } | |
765 | ||
9346a6ac | 766 | fn walk_autoderefref(&mut self, |
e9174d1e SL |
767 | expr: &hir::Expr, |
768 | adj: &adjustment::AutoDerefRef<'tcx>) { | |
62682a34 SL |
769 | debug!("walk_autoderefref expr={:?} adj={:?}", |
770 | expr, | |
771 | adj); | |
9346a6ac AL |
772 | |
773 | self.walk_autoderefs(expr, adj.autoderefs); | |
774 | ||
775 | let cmt_derefd = | |
776 | return_if_err!(self.mc.cat_expr_autoderefd(expr, adj.autoderefs)); | |
777 | ||
778 | let cmt_refd = | |
779 | self.walk_autoref(expr, cmt_derefd, adj.autoref); | |
780 | ||
781 | if adj.unsize.is_some() { | |
782 | // Unsizing consumes the thin pointer and produces a fat one. | |
783 | self.delegate_consume(expr.id, expr.span, cmt_refd); | |
784 | } | |
785 | } | |
786 | ||
787 | ||
788 | /// Walks the autoref `opt_autoref` applied to the autoderef'd | |
789 | /// `expr`. `cmt_derefd` is the mem-categorized form of `expr` | |
790 | /// after all relevant autoderefs have occurred. Because AutoRefs | |
791 | /// can be recursive, this function is recursive: it first walks | |
792 | /// deeply all the way down the autoref chain, and then processes | |
793 | /// the autorefs on the way out. At each point, it returns the | |
794 | /// `cmt` for the rvalue that will be produced by introduced an | |
795 | /// autoref. | |
1a4d82fc | 796 | fn walk_autoref(&mut self, |
e9174d1e | 797 | expr: &hir::Expr, |
9346a6ac | 798 | cmt_base: mc::cmt<'tcx>, |
e9174d1e | 799 | opt_autoref: Option<adjustment::AutoRef<'tcx>>) |
9346a6ac AL |
800 | -> mc::cmt<'tcx> |
801 | { | |
62682a34 | 802 | debug!("walk_autoref(expr.id={} cmt_derefd={:?} opt_autoref={:?})", |
9346a6ac | 803 | expr.id, |
62682a34 | 804 | cmt_base, |
9346a6ac AL |
805 | opt_autoref); |
806 | ||
807 | let cmt_base_ty = cmt_base.ty; | |
808 | ||
809 | let autoref = match opt_autoref { | |
810 | Some(ref autoref) => autoref, | |
811 | None => { | |
812 | // No AutoRef. | |
813 | return cmt_base; | |
814 | } | |
815 | }; | |
1a4d82fc | 816 | |
9346a6ac | 817 | match *autoref { |
e9174d1e | 818 | adjustment::AutoPtr(r, m) => { |
1a4d82fc JJ |
819 | self.delegate.borrow(expr.id, |
820 | expr.span, | |
9346a6ac AL |
821 | cmt_base, |
822 | *r, | |
1a4d82fc JJ |
823 | ty::BorrowKind::from_mutbl(m), |
824 | AutoRef); | |
825 | } | |
9346a6ac | 826 | |
e9174d1e | 827 | adjustment::AutoUnsafe(m) => { |
62682a34 | 828 | debug!("walk_autoref: expr.id={} cmt_base={:?}", |
9346a6ac | 829 | expr.id, |
62682a34 | 830 | cmt_base); |
9346a6ac AL |
831 | |
832 | // Converting from a &T to *T (or &mut T to *mut T) is | |
833 | // treated as borrowing it for the enclosing temporary | |
834 | // scope. | |
e9174d1e | 835 | let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); |
9346a6ac AL |
836 | |
837 | self.delegate.borrow(expr.id, | |
838 | expr.span, | |
839 | cmt_base, | |
840 | r, | |
841 | ty::BorrowKind::from_mutbl(m), | |
842 | AutoUnsafe); | |
c34b1796 | 843 | } |
1a4d82fc | 844 | } |
9346a6ac AL |
845 | |
846 | // Construct the categorization for the result of the autoref. | |
847 | // This is always an rvalue, since we are producing a new | |
848 | // (temporary) indirection. | |
849 | ||
c1a9b12d | 850 | let adj_ty = cmt_base_ty.adjust_for_autoref(self.tcx(), opt_autoref); |
9346a6ac AL |
851 | |
852 | self.mc.cat_rvalue_node(expr.id, expr.span, adj_ty) | |
1a4d82fc JJ |
853 | } |
854 | ||
9346a6ac | 855 | |
c34b1796 AL |
856 | // When this returns true, it means that the expression *is* a |
857 | // method-call (i.e. via the operator-overload). This true result | |
858 | // also implies that walk_overloaded_operator already took care of | |
859 | // recursively processing the input arguments, and thus the caller | |
860 | // should not do so. | |
1a4d82fc | 861 | fn walk_overloaded_operator(&mut self, |
e9174d1e SL |
862 | expr: &hir::Expr, |
863 | receiver: &hir::Expr, | |
864 | rhs: Vec<&hir::Expr>, | |
1a4d82fc JJ |
865 | pass_args: PassArgs) |
866 | -> bool | |
867 | { | |
868 | if !self.typer.is_method_call(expr.id) { | |
869 | return false; | |
870 | } | |
871 | ||
872 | match pass_args { | |
873 | PassArgs::ByValue => { | |
874 | self.consume_expr(receiver); | |
85aaf69f | 875 | for &arg in &rhs { |
1a4d82fc JJ |
876 | self.consume_expr(arg); |
877 | } | |
878 | ||
879 | return true; | |
880 | }, | |
881 | PassArgs::ByRef => {}, | |
882 | } | |
883 | ||
884 | self.walk_expr(receiver); | |
885 | ||
886 | // Arguments (but not receivers) to overloaded operator | |
887 | // methods are implicitly autoref'd which sadly does not use | |
888 | // adjustments, so we must hardcode the borrow here. | |
889 | ||
e9174d1e | 890 | let r = ty::ReScope(self.tcx().region_maps.node_extent(expr.id)); |
1a4d82fc JJ |
891 | let bk = ty::ImmBorrow; |
892 | ||
85aaf69f | 893 | for &arg in &rhs { |
1a4d82fc JJ |
894 | self.borrow_expr(arg, r, bk, OverloadedOperator); |
895 | } | |
896 | return true; | |
897 | } | |
898 | ||
e9174d1e | 899 | fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode { |
1a4d82fc | 900 | let mut mode = Unknown; |
85aaf69f | 901 | for pat in &arm.pats { |
7453a54e | 902 | self.determine_pat_move_mode(discr_cmt.clone(), &pat, &mut mode); |
1a4d82fc JJ |
903 | } |
904 | mode | |
905 | } | |
906 | ||
e9174d1e | 907 | fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, mode: MatchMode) { |
85aaf69f | 908 | for pat in &arm.pats { |
7453a54e | 909 | self.walk_pat(discr_cmt.clone(), &pat, mode); |
1a4d82fc JJ |
910 | } |
911 | ||
85aaf69f | 912 | if let Some(ref guard) = arm.guard { |
7453a54e | 913 | self.consume_expr(&guard); |
1a4d82fc JJ |
914 | } |
915 | ||
7453a54e | 916 | self.consume_expr(&arm.body); |
1a4d82fc JJ |
917 | } |
918 | ||
b039eaaf | 919 | /// Walks a pat that occurs in isolation (i.e. top-level of fn |
1a4d82fc | 920 | /// arg or let binding. *Not* a match arm or nested pat.) |
e9174d1e | 921 | fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) { |
1a4d82fc JJ |
922 | let mut mode = Unknown; |
923 | self.determine_pat_move_mode(cmt_discr.clone(), pat, &mut mode); | |
924 | let mode = mode.match_mode(); | |
925 | self.walk_pat(cmt_discr, pat, mode); | |
926 | } | |
927 | ||
928 | /// Identifies any bindings within `pat` and accumulates within | |
929 | /// `mode` whether the overall pattern/match structure is a move, | |
930 | /// copy, or borrow. | |
931 | fn determine_pat_move_mode(&mut self, | |
932 | cmt_discr: mc::cmt<'tcx>, | |
e9174d1e | 933 | pat: &hir::Pat, |
85aaf69f | 934 | mode: &mut TrackMatchMode) { |
62682a34 SL |
935 | debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr, |
936 | pat); | |
1a4d82fc | 937 | return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| { |
1a4d82fc | 938 | let def_map = &self.tcx().def_map; |
92a42be0 | 939 | if pat_util::pat_is_binding(&def_map.borrow(), pat) { |
1a4d82fc | 940 | match pat.node { |
7453a54e | 941 | PatKind::Ident(hir::BindByRef(_), _, _) => |
1a4d82fc | 942 | mode.lub(BorrowingMatch), |
7453a54e | 943 | PatKind::Ident(hir::BindByValue(_), _, _) => { |
1a4d82fc JJ |
944 | match copy_or_move(self.typer, &cmt_pat, PatBindingMove) { |
945 | Copy => mode.lub(CopyingMatch), | |
946 | Move(_) => mode.lub(MovingMatch), | |
947 | } | |
948 | } | |
949 | _ => { | |
54a0048b | 950 | span_bug!( |
1a4d82fc JJ |
951 | pat.span, |
952 | "binding pattern not an identifier"); | |
953 | } | |
954 | } | |
955 | } | |
956 | })); | |
957 | } | |
958 | ||
959 | /// The core driver for walking a pattern; `match_mode` must be | |
960 | /// established up front, e.g. via `determine_pat_move_mode` (see | |
961 | /// also `walk_irrefutable_pat` for patterns that stand alone). | |
962 | fn walk_pat(&mut self, | |
963 | cmt_discr: mc::cmt<'tcx>, | |
e9174d1e | 964 | pat: &hir::Pat, |
1a4d82fc | 965 | match_mode: MatchMode) { |
62682a34 SL |
966 | debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, |
967 | pat); | |
1a4d82fc JJ |
968 | |
969 | let mc = &self.mc; | |
970 | let typer = self.typer; | |
971 | let def_map = &self.tcx().def_map; | |
972 | let delegate = &mut self.delegate; | |
973 | return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| { | |
92a42be0 | 974 | if pat_util::pat_is_binding(&def_map.borrow(), pat) { |
62682a34 SL |
975 | debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", |
976 | cmt_pat, | |
977 | pat, | |
1a4d82fc JJ |
978 | match_mode); |
979 | ||
980 | // pat_ty: the type of the binding being produced. | |
981 | let pat_ty = return_if_err!(typer.node_ty(pat.id)); | |
982 | ||
983 | // Each match binding is effectively an assignment to the | |
984 | // binding being produced. | |
c34b1796 | 985 | let def = def_map.borrow().get(&pat.id).unwrap().full_def(); |
1a4d82fc JJ |
986 | match mc.cat_def(pat.id, pat.span, pat_ty, def) { |
987 | Ok(binding_cmt) => { | |
9cc50fc6 | 988 | delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); |
1a4d82fc JJ |
989 | } |
990 | Err(_) => { } | |
991 | } | |
992 | ||
993 | // It is also a borrow or copy/move of the value being matched. | |
994 | match pat.node { | |
7453a54e | 995 | PatKind::Ident(hir::BindByRef(m), _, _) => { |
c1a9b12d SL |
996 | if let ty::TyRef(&r, _) = pat_ty.sty { |
997 | let bk = ty::BorrowKind::from_mutbl(m); | |
998 | delegate.borrow(pat.id, pat.span, cmt_pat, | |
999 | r, bk, RefBinding); | |
1000 | } | |
1a4d82fc | 1001 | } |
7453a54e | 1002 | PatKind::Ident(hir::BindByValue(_), _, _) => { |
1a4d82fc JJ |
1003 | let mode = copy_or_move(typer, &cmt_pat, PatBindingMove); |
1004 | debug!("walk_pat binding consuming pat"); | |
1005 | delegate.consume_pat(pat, cmt_pat, mode); | |
1006 | } | |
1007 | _ => { | |
54a0048b | 1008 | span_bug!( |
1a4d82fc JJ |
1009 | pat.span, |
1010 | "binding pattern not an identifier"); | |
1011 | } | |
1012 | } | |
1013 | } else { | |
1014 | match pat.node { | |
7453a54e | 1015 | PatKind::Vec(_, Some(ref slice_pat), _) => { |
1a4d82fc JJ |
1016 | // The `slice_pat` here creates a slice into |
1017 | // the original vector. This is effectively a | |
1018 | // borrow of the elements of the vector being | |
1019 | // matched. | |
1020 | ||
1021 | let (slice_cmt, slice_mutbl, slice_r) = | |
7453a54e | 1022 | return_if_err!(mc.cat_slice_pattern(cmt_pat, &slice_pat)); |
1a4d82fc JJ |
1023 | |
1024 | // Note: We declare here that the borrow | |
1025 | // occurs upon entering the `[...]` | |
1026 | // pattern. This implies that something like | |
1027 | // `[a; b]` where `a` is a move is illegal, | |
1028 | // because the borrow is already in effect. | |
1029 | // In fact such a move would be safe-ish, but | |
1030 | // it effectively *requires* that we use the | |
1031 | // nulling out semantics to indicate when a | |
1032 | // value has been moved, which we are trying | |
1033 | // to move away from. Otherwise, how can we | |
1034 | // indicate that the first element in the | |
1035 | // vector has been moved? Eventually, we | |
1036 | // could perhaps modify this rule to permit | |
1037 | // `[..a, b]` where `b` is a move, because in | |
1038 | // that case we can adjust the length of the | |
1039 | // original vec accordingly, but we'd have to | |
1040 | // make trans do the right thing, and it would | |
d9579d0f | 1041 | // only work for `Box<[T]>`s. It seems simpler |
1a4d82fc JJ |
1042 | // to just require that people call |
1043 | // `vec.pop()` or `vec.unshift()`. | |
1044 | let slice_bk = ty::BorrowKind::from_mutbl(slice_mutbl); | |
1045 | delegate.borrow(pat.id, pat.span, | |
1046 | slice_cmt, slice_r, | |
1047 | slice_bk, RefBinding); | |
1048 | } | |
1049 | _ => { } | |
1050 | } | |
1051 | } | |
1052 | })); | |
1053 | ||
1054 | // Do a second pass over the pattern, calling `matched_pat` on | |
1055 | // the interior nodes (enum variants and structs), as opposed | |
1056 | // to the above loop's visit of than the bindings that form | |
1057 | // the leaves of the pattern tree structure. | |
1058 | return_if_err!(mc.cat_pattern(cmt_discr, pat, |mc, cmt_pat, pat| { | |
1059 | let def_map = def_map.borrow(); | |
c1a9b12d | 1060 | let tcx = typer.tcx; |
1a4d82fc JJ |
1061 | |
1062 | match pat.node { | |
7453a54e SL |
1063 | PatKind::TupleStruct(..) | PatKind::Path(..) | PatKind::QPath(..) | |
1064 | PatKind::Ident(_, _, None) | PatKind::Struct(..) => { | |
c34b1796 | 1065 | match def_map.get(&pat.id).map(|d| d.full_def()) { |
1a4d82fc JJ |
1066 | None => { |
1067 | // no definition found: pat is not a | |
1068 | // struct or enum pattern. | |
1069 | } | |
1070 | ||
7453a54e | 1071 | Some(Def::Variant(enum_did, variant_did)) => { |
1a4d82fc | 1072 | let downcast_cmt = |
e9174d1e | 1073 | if tcx.lookup_adt_def(enum_did).is_univariant() { |
1a4d82fc JJ |
1074 | cmt_pat |
1075 | } else { | |
1076 | let cmt_pat_ty = cmt_pat.ty; | |
1077 | mc.cat_downcast(pat, cmt_pat, cmt_pat_ty, variant_did) | |
1078 | }; | |
1079 | ||
62682a34 SL |
1080 | debug!("variant downcast_cmt={:?} pat={:?}", |
1081 | downcast_cmt, | |
1082 | pat); | |
1a4d82fc JJ |
1083 | |
1084 | delegate.matched_pat(pat, downcast_cmt, match_mode); | |
1085 | } | |
1086 | ||
7453a54e | 1087 | Some(Def::Struct(..)) | Some(Def::TyAlias(..)) => { |
1a4d82fc JJ |
1088 | // A struct (in either the value or type |
1089 | // namespace; we encounter the former on | |
1090 | // e.g. patterns for unit structs). | |
1091 | ||
62682a34 SL |
1092 | debug!("struct cmt_pat={:?} pat={:?}", |
1093 | cmt_pat, | |
1094 | pat); | |
1a4d82fc JJ |
1095 | |
1096 | delegate.matched_pat(pat, cmt_pat, match_mode); | |
1097 | } | |
1098 | ||
7453a54e SL |
1099 | Some(Def::Const(..)) | |
1100 | Some(Def::AssociatedConst(..)) | | |
1101 | Some(Def::Local(..)) => { | |
1a4d82fc JJ |
1102 | // This is a leaf (i.e. identifier binding |
1103 | // or constant value to match); thus no | |
1104 | // `matched_pat` call. | |
1105 | } | |
1106 | ||
1a4d82fc | 1107 | Some(def) => { |
7453a54e SL |
1108 | // An enum type should never be in a pattern. |
1109 | // Remaining cases are e.g. Def::Fn, to | |
1a4d82fc JJ |
1110 | // which identifiers within patterns |
1111 | // should not resolve. However, we do | |
1112 | // encouter this when using the | |
1113 | // expr-use-visitor during typeck. So just | |
1114 | // ignore it, an error should have been | |
1115 | // reported. | |
1116 | ||
1117 | if !tcx.sess.has_errors() { | |
54a0048b SL |
1118 | span_bug!(pat.span, |
1119 | "Pattern has unexpected def: {:?} and type {:?}", | |
1120 | def, | |
1121 | cmt_pat.ty); | |
1a4d82fc JJ |
1122 | } |
1123 | } | |
1124 | } | |
1125 | } | |
1126 | ||
7453a54e | 1127 | PatKind::Ident(_, _, Some(_)) => { |
b039eaaf | 1128 | // Do nothing; this is a binding (not an enum |
1a4d82fc JJ |
1129 | // variant or struct), and the cat_pattern call |
1130 | // will visit the substructure recursively. | |
1131 | } | |
1132 | ||
7453a54e SL |
1133 | PatKind::Wild | PatKind::Tup(..) | PatKind::Box(..) | |
1134 | PatKind::Ref(..) | PatKind::Lit(..) | PatKind::Range(..) | | |
1135 | PatKind::Vec(..) => { | |
1a4d82fc | 1136 | // Similarly, each of these cases does not |
b039eaaf | 1137 | // correspond to an enum variant or struct, so we |
1a4d82fc JJ |
1138 | // do not do any `matched_pat` calls for these |
1139 | // cases either. | |
1140 | } | |
1141 | } | |
1142 | })); | |
1143 | } | |
1144 | ||
e9174d1e | 1145 | fn walk_captures(&mut self, closure_expr: &hir::Expr) { |
62682a34 | 1146 | debug!("walk_captures({:?})", closure_expr); |
1a4d82fc | 1147 | |
c1a9b12d | 1148 | self.tcx().with_freevars(closure_expr.id, |freevars| { |
85aaf69f | 1149 | for freevar in freevars { |
b039eaaf | 1150 | let id_var = freevar.def.var_id(); |
85aaf69f SL |
1151 | let upvar_id = ty::UpvarId { var_id: id_var, |
1152 | closure_expr_id: closure_expr.id }; | |
1153 | let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap(); | |
1154 | let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id, | |
1155 | closure_expr.span, | |
1156 | freevar.def)); | |
1157 | match upvar_capture { | |
1158 | ty::UpvarCapture::ByValue => { | |
1159 | let mode = copy_or_move(self.typer, &cmt_var, CaptureMove); | |
1160 | self.delegate.consume(closure_expr.id, freevar.span, cmt_var, mode); | |
1161 | } | |
1162 | ty::UpvarCapture::ByRef(upvar_borrow) => { | |
1163 | self.delegate.borrow(closure_expr.id, | |
1164 | closure_expr.span, | |
1165 | cmt_var, | |
1166 | upvar_borrow.region, | |
1167 | upvar_borrow.kind, | |
1168 | ClosureCapture(freevar.span)); | |
1169 | } | |
1a4d82fc JJ |
1170 | } |
1171 | } | |
1172 | }); | |
1173 | } | |
1174 | ||
1a4d82fc JJ |
1175 | fn cat_captured_var(&mut self, |
1176 | closure_id: ast::NodeId, | |
1177 | closure_span: Span, | |
7453a54e | 1178 | upvar_def: Def) |
1a4d82fc JJ |
1179 | -> mc::McResult<mc::cmt<'tcx>> { |
1180 | // Create the cmt for the variable being borrowed, from the | |
1181 | // caller's perspective | |
b039eaaf | 1182 | let var_id = upvar_def.var_id(); |
54a0048b | 1183 | let var_ty = self.typer.node_ty(var_id)?; |
1a4d82fc JJ |
1184 | self.mc.cat_def(closure_id, closure_span, var_ty, upvar_def) |
1185 | } | |
1186 | } | |
1187 | ||
c1a9b12d | 1188 | fn copy_or_move<'a, 'tcx>(typer: &infer::InferCtxt<'a, 'tcx>, |
1a4d82fc JJ |
1189 | cmt: &mc::cmt<'tcx>, |
1190 | move_reason: MoveReason) | |
1191 | -> ConsumeMode | |
1192 | { | |
c1a9b12d | 1193 | if typer.type_moves_by_default(cmt.ty, cmt.span) { |
1a4d82fc JJ |
1194 | Move(move_reason) |
1195 | } else { | |
1196 | Copy | |
1197 | } | |
1198 | } |