]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/mem_categorization.rs
Auto merge of #27549 - tshepang:clarity, r=alexcrichton
[rust.git] / src / librustc / middle / mem_categorization.rs
1 // Copyright 2012-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 //! # Categorization
12 //!
13 //! The job of the categorization module is to analyze an expression to
14 //! determine what kind of memory is used in evaluating it (for example,
15 //! where dereferences occur and what kind of pointer is dereferenced;
16 //! whether the memory is mutable; etc)
17 //!
18 //! Categorization effectively transforms all of our expressions into
19 //! expressions of the following forms (the actual enum has many more
20 //! possibilities, naturally, but they are all variants of these base
21 //! forms):
22 //!
23 //!     E = rvalue    // some computed rvalue
24 //!       | x         // address of a local variable or argument
25 //!       | *E        // deref of a ptr
26 //!       | E.comp    // access to an interior component
27 //!
28 //! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
29 //! address where the result is to be found.  If Expr is an lvalue, then this
30 //! is the address of the lvalue.  If Expr is an rvalue, this is the address of
31 //! some temporary spot in memory where the result is stored.
32 //!
33 //! Now, cat_expr() classifies the expression Expr and the address A=ToAddr(Expr)
34 //! as follows:
35 //!
36 //! - cat: what kind of expression was this?  This is a subset of the
37 //!   full expression forms which only includes those that we care about
38 //!   for the purpose of the analysis.
39 //! - mutbl: mutability of the address A
40 //! - ty: the type of data found at the address A
41 //!
42 //! The resulting categorization tree differs somewhat from the expressions
43 //! themselves.  For example, auto-derefs are explicit.  Also, an index a[b] is
44 //! decomposed into two operations: a dereference to reach the array data and
45 //! then an index to jump forward to the relevant item.
46 //!
47 //! ## By-reference upvars
48 //!
49 //! One part of the translation which may be non-obvious is that we translate
50 //! closure upvars into the dereference of a borrowed pointer; this more closely
51 //! resembles the runtime translation. So, for example, if we had:
52 //!
53 //!     let mut x = 3;
54 //!     let y = 5;
55 //!     let inc = || x += y;
56 //!
57 //! Then when we categorize `x` (*within* the closure) we would yield a
58 //! result of `*x'`, effectively, where `x'` is a `cat_upvar` reference
59 //! tied to `x`. The type of `x'` will be a borrowed pointer.
60
61 #![allow(non_camel_case_types)]
62
63 pub use self::PointerKind::*;
64 pub use self::InteriorKind::*;
65 pub use self::FieldName::*;
66 pub use self::ElementKind::*;
67 pub use self::MutabilityCategory::*;
68 pub use self::AliasableReason::*;
69 pub use self::Note::*;
70 pub use self::deref_kind::*;
71 pub use self::categorization::*;
72
73 use self::Aliasability::*;
74
75 use ast_map;
76 use middle::infer;
77 use middle::check_const;
78 use middle::def;
79 use middle::region;
80 use middle::ty::{self, Ty};
81
82 use syntax::ast::{MutImmutable, MutMutable};
83 use syntax::ast;
84 use syntax::codemap::Span;
85
86 use std::fmt;
87 use std::rc::Rc;
88
89 #[derive(Clone, PartialEq)]
90 pub enum categorization<'tcx> {
91     cat_rvalue(ty::Region),                    // temporary val, argument is its scope
92     cat_static_item,
93     cat_upvar(Upvar),                          // upvar referenced by closure env
94     cat_local(ast::NodeId),                    // local variable
95     cat_deref(cmt<'tcx>, usize, PointerKind),   // deref of a ptr
96     cat_interior(cmt<'tcx>, InteriorKind),     // something interior: field, tuple, etc
97     cat_downcast(cmt<'tcx>, ast::DefId),       // selects a particular enum variant (*1)
98
99     // (*1) downcast is only required if the enum has more than one variant
100 }
101
102 // Represents any kind of upvar
103 #[derive(Clone, Copy, PartialEq)]
104 pub struct Upvar {
105     pub id: ty::UpvarId,
106     pub kind: ty::ClosureKind
107 }
108
109 // different kinds of pointers:
110 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
111 pub enum PointerKind {
112     /// `Box<T>`
113     Unique,
114
115     /// `&T`
116     BorrowedPtr(ty::BorrowKind, ty::Region),
117
118     /// `*T`
119     UnsafePtr(ast::Mutability),
120
121     /// Implicit deref of the `&T` that results from an overloaded index `[]`.
122     Implicit(ty::BorrowKind, ty::Region),
123 }
124
125 // We use the term "interior" to mean "something reachable from the
126 // base without a pointer dereference", e.g. a field
127 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
128 pub enum InteriorKind {
129     InteriorField(FieldName),
130     InteriorElement(InteriorOffsetKind, ElementKind),
131 }
132
133 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
134 pub enum FieldName {
135     NamedField(ast::Name),
136     PositionalField(usize)
137 }
138
139 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
140 pub enum InteriorOffsetKind {
141     Index,            // e.g. `array_expr[index_expr]`
142     Pattern,          // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
143 }
144
145 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
146 pub enum ElementKind {
147     VecElement,
148     OtherElement,
149 }
150
151 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
152 pub enum MutabilityCategory {
153     McImmutable, // Immutable.
154     McDeclared,  // Directly declared as mutable.
155     McInherited, // Inherited from the fact that owner is mutable.
156 }
157
158 // A note about the provenance of a `cmt`.  This is used for
159 // special-case handling of upvars such as mutability inference.
160 // Upvar categorization can generate a variable number of nested
161 // derefs.  The note allows detecting them without deep pattern
162 // matching on the categorization.
163 #[derive(Clone, Copy, PartialEq, Debug)]
164 pub enum Note {
165     NoteClosureEnv(ty::UpvarId), // Deref through closure env
166     NoteUpvarRef(ty::UpvarId),   // Deref through by-ref upvar
167     NoteNone                     // Nothing special
168 }
169
170 // `cmt`: "Category, Mutability, and Type".
171 //
172 // a complete categorization of a value indicating where it originated
173 // and how it is located, as well as the mutability of the memory in
174 // which the value is stored.
175 //
176 // *WARNING* The field `cmt.type` is NOT necessarily the same as the
177 // result of `node_id_to_type(cmt.id)`. This is because the `id` is
178 // always the `id` of the node producing the type; in an expression
179 // like `*x`, the type of this deref node is the deref'd type (`T`),
180 // but in a pattern like `@x`, the `@x` pattern is again a
181 // dereference, but its type is the type *before* the dereference
182 // (`@T`). So use `cmt.ty` to find the type of the value in a consistent
183 // fashion. For more details, see the method `cat_pattern`
184 #[derive(Clone, PartialEq)]
185 pub struct cmt_<'tcx> {
186     pub id: ast::NodeId,           // id of expr/pat producing this value
187     pub span: Span,                // span of same expr/pat
188     pub cat: categorization<'tcx>, // categorization of expr
189     pub mutbl: MutabilityCategory, // mutability of expr as lvalue
190     pub ty: Ty<'tcx>,              // type of the expr (*see WARNING above*)
191     pub note: Note,                // Note about the provenance of this cmt
192 }
193
194 pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
195
196 // We pun on *T to mean both actual deref of a ptr as well
197 // as accessing of components:
198 #[derive(Copy, Clone)]
199 pub enum deref_kind {
200     deref_ptr(PointerKind),
201     deref_interior(InteriorKind),
202 }
203
204 type DerefKindContext = Option<InteriorOffsetKind>;
205
206 // Categorizes a derefable type.  Note that we include vectors and strings as
207 // derefable (we model an index as the combination of a deref and then a
208 // pointer adjustment).
209 fn deref_kind(t: Ty, context: DerefKindContext) -> McResult<deref_kind> {
210     match t.sty {
211         ty::TyBox(_) => {
212             Ok(deref_ptr(Unique))
213         }
214
215         ty::TyRef(r, mt) => {
216             let kind = ty::BorrowKind::from_mutbl(mt.mutbl);
217             Ok(deref_ptr(BorrowedPtr(kind, *r)))
218         }
219
220         ty::TyRawPtr(ref mt) => {
221             Ok(deref_ptr(UnsafePtr(mt.mutbl)))
222         }
223
224         ty::TyEnum(..) |
225         ty::TyStruct(..) => { // newtype
226             Ok(deref_interior(InteriorField(PositionalField(0))))
227         }
228
229         ty::TyArray(_, _) | ty::TySlice(_) | ty::TyStr => {
230             // no deref of indexed content without supplying InteriorOffsetKind
231             if let Some(context) = context {
232                 Ok(deref_interior(InteriorElement(context, element_kind(t))))
233             } else {
234                 Err(())
235             }
236         }
237
238         _ => Err(()),
239     }
240 }
241
242 pub trait ast_node {
243     fn id(&self) -> ast::NodeId;
244     fn span(&self) -> Span;
245 }
246
247 impl ast_node for ast::Expr {
248     fn id(&self) -> ast::NodeId { self.id }
249     fn span(&self) -> Span { self.span }
250 }
251
252 impl ast_node for ast::Pat {
253     fn id(&self) -> ast::NodeId { self.id }
254     fn span(&self) -> Span { self.span }
255 }
256
257 #[derive(Copy, Clone)]
258 pub struct MemCategorizationContext<'t, 'a: 't, 'tcx : 'a> {
259     pub typer: &'t infer::InferCtxt<'a, 'tcx>,
260 }
261
262 pub type McResult<T> = Result<T, ()>;
263
264 impl MutabilityCategory {
265     pub fn from_mutbl(m: ast::Mutability) -> MutabilityCategory {
266         let ret = match m {
267             MutImmutable => McImmutable,
268             MutMutable => McDeclared
269         };
270         debug!("MutabilityCategory::{}({:?}) => {:?}",
271                "from_mutbl", m, ret);
272         ret
273     }
274
275     pub fn from_borrow_kind(borrow_kind: ty::BorrowKind) -> MutabilityCategory {
276         let ret = match borrow_kind {
277             ty::ImmBorrow => McImmutable,
278             ty::UniqueImmBorrow => McImmutable,
279             ty::MutBorrow => McDeclared,
280         };
281         debug!("MutabilityCategory::{}({:?}) => {:?}",
282                "from_borrow_kind", borrow_kind, ret);
283         ret
284     }
285
286     fn from_pointer_kind(base_mutbl: MutabilityCategory,
287                          ptr: PointerKind) -> MutabilityCategory {
288         let ret = match ptr {
289             Unique => {
290                 base_mutbl.inherit()
291             }
292             BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
293                 MutabilityCategory::from_borrow_kind(borrow_kind)
294             }
295             UnsafePtr(m) => {
296                 MutabilityCategory::from_mutbl(m)
297             }
298         };
299         debug!("MutabilityCategory::{}({:?}, {:?}) => {:?}",
300                "from_pointer_kind", base_mutbl, ptr, ret);
301         ret
302     }
303
304     fn from_local(tcx: &ty::ctxt, id: ast::NodeId) -> MutabilityCategory {
305         let ret = match tcx.map.get(id) {
306             ast_map::NodeLocal(p) | ast_map::NodeArg(p) => match p.node {
307                 ast::PatIdent(bind_mode, _, _) => {
308                     if bind_mode == ast::BindByValue(ast::MutMutable) {
309                         McDeclared
310                     } else {
311                         McImmutable
312                     }
313                 }
314                 _ => tcx.sess.span_bug(p.span, "expected identifier pattern")
315             },
316             _ => tcx.sess.span_bug(tcx.map.span(id), "expected identifier pattern")
317         };
318         debug!("MutabilityCategory::{}(tcx, id={:?}) => {:?}",
319                "from_local", id, ret);
320         ret
321     }
322
323     pub fn inherit(&self) -> MutabilityCategory {
324         let ret = match *self {
325             McImmutable => McImmutable,
326             McDeclared => McInherited,
327             McInherited => McInherited,
328         };
329         debug!("{:?}.inherit() => {:?}", self, ret);
330         ret
331     }
332
333     pub fn is_mutable(&self) -> bool {
334         let ret = match *self {
335             McImmutable => false,
336             McInherited => true,
337             McDeclared => true,
338         };
339         debug!("{:?}.is_mutable() => {:?}", self, ret);
340         ret
341     }
342
343     pub fn is_immutable(&self) -> bool {
344         let ret = match *self {
345             McImmutable => true,
346             McDeclared | McInherited => false
347         };
348         debug!("{:?}.is_immutable() => {:?}", self, ret);
349         ret
350     }
351
352     pub fn to_user_str(&self) -> &'static str {
353         match *self {
354             McDeclared | McInherited => "mutable",
355             McImmutable => "immutable",
356         }
357     }
358 }
359
360 impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> {
361     pub fn new(typer: &'t infer::InferCtxt<'a, 'tcx>) -> MemCategorizationContext<'t, 'a, 'tcx> {
362         MemCategorizationContext { typer: typer }
363     }
364
365     fn tcx(&self) -> &'a ty::ctxt<'tcx> {
366         self.typer.tcx
367     }
368
369     fn expr_ty(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
370         match self.typer.node_ty(expr.id) {
371             Ok(t) => Ok(t),
372             Err(()) => {
373                 debug!("expr_ty({:?}) yielded Err", expr);
374                 Err(())
375             }
376         }
377     }
378
379     fn expr_ty_adjusted(&self, expr: &ast::Expr) -> McResult<Ty<'tcx>> {
380         let unadjusted_ty = try!(self.expr_ty(expr));
381         Ok(unadjusted_ty.adjust(
382             self.tcx(), expr.span, expr.id,
383             self.typer.adjustments().get(&expr.id),
384             |method_call| self.typer.node_method_ty(method_call)))
385     }
386
387     fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
388         self.typer.node_ty(id)
389     }
390
391     fn pat_ty(&self, pat: &ast::Pat) -> McResult<Ty<'tcx>> {
392         let base_ty = try!(self.typer.node_ty(pat.id));
393         // FIXME (Issue #18207): This code detects whether we are
394         // looking at a `ref x`, and if so, figures out what the type
395         // *being borrowed* is.  But ideally we would put in a more
396         // fundamental fix to this conflated use of the node id.
397         let ret_ty = match pat.node {
398             ast::PatIdent(ast::BindByRef(_), _, _) => {
399                 // a bind-by-ref means that the base_ty will be the type of the ident itself,
400                 // but what we want here is the type of the underlying value being borrowed.
401                 // So peel off one-level, turning the &T into T.
402                 match base_ty.builtin_deref(false) {
403                     Some(t) => t.ty,
404                     None => { return Err(()); }
405                 }
406             }
407             _ => base_ty,
408         };
409         debug!("pat_ty(pat={:?}) base_ty={:?} ret_ty={:?}",
410                pat, base_ty, ret_ty);
411         Ok(ret_ty)
412     }
413
414     pub fn cat_expr(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
415         match self.typer.adjustments().get(&expr.id) {
416             None => {
417                 // No adjustments.
418                 self.cat_expr_unadjusted(expr)
419             }
420
421             Some(adjustment) => {
422                 match *adjustment {
423                     ty::AdjustDerefRef(
424                         ty::AutoDerefRef {
425                             autoref: None, unsize: None, autoderefs, ..}) => {
426                         // Equivalent to *expr or something similar.
427                         self.cat_expr_autoderefd(expr, autoderefs)
428                     }
429
430                     ty::AdjustReifyFnPointer |
431                     ty::AdjustUnsafeFnPointer |
432                     ty::AdjustDerefRef(_) => {
433                         debug!("cat_expr({:?}): {:?}",
434                                adjustment,
435                                expr);
436                         // Result is an rvalue.
437                         let expr_ty = try!(self.expr_ty_adjusted(expr));
438                         Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
439                     }
440                 }
441             }
442         }
443     }
444
445     pub fn cat_expr_autoderefd(&self,
446                                expr: &ast::Expr,
447                                autoderefs: usize)
448                                -> McResult<cmt<'tcx>> {
449         let mut cmt = try!(self.cat_expr_unadjusted(expr));
450         debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
451                autoderefs,
452                cmt);
453         for deref in 1..autoderefs + 1 {
454             cmt = try!(self.cat_deref(expr, cmt, deref, None));
455         }
456         return Ok(cmt);
457     }
458
459     pub fn cat_expr_unadjusted(&self, expr: &ast::Expr) -> McResult<cmt<'tcx>> {
460         debug!("cat_expr: id={} expr={:?}", expr.id, expr);
461
462         let expr_ty = try!(self.expr_ty(expr));
463         match expr.node {
464           ast::ExprUnary(ast::UnDeref, ref e_base) => {
465             let base_cmt = try!(self.cat_expr(&**e_base));
466             self.cat_deref(expr, base_cmt, 0, None)
467           }
468
469           ast::ExprField(ref base, f_name) => {
470             let base_cmt = try!(self.cat_expr(&**base));
471             debug!("cat_expr(cat_field): id={} expr={:?} base={:?}",
472                    expr.id,
473                    expr,
474                    base_cmt);
475             Ok(self.cat_field(expr, base_cmt, f_name.node.name, expr_ty))
476           }
477
478           ast::ExprTupField(ref base, idx) => {
479             let base_cmt = try!(self.cat_expr(&**base));
480             Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty))
481           }
482
483           ast::ExprIndex(ref base, _) => {
484             let method_call = ty::MethodCall::expr(expr.id());
485             let context = InteriorOffsetKind::Index;
486             match self.typer.node_method_ty(method_call) {
487                 Some(method_ty) => {
488                     // If this is an index implemented by a method call, then it
489                     // will include an implicit deref of the result.
490                     let ret_ty = self.overloaded_method_return_ty(method_ty);
491
492                     // The index method always returns an `&T`, so
493                     // dereference it to find the result type.
494                     let elem_ty = match ret_ty.sty {
495                         ty::TyRef(_, mt) => mt.ty,
496                         _ => {
497                             debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
498                                    ret_ty);
499                             return Err(());
500                         }
501                     };
502
503                     // The call to index() returns a `&T` value, which
504                     // is an rvalue. That is what we will be
505                     // dereferencing.
506                     let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
507                     self.cat_deref_common(expr, base_cmt, 1, elem_ty, Some(context), true)
508                 }
509                 None => {
510                     self.cat_index(expr, try!(self.cat_expr(&**base)), context)
511                 }
512             }
513           }
514
515           ast::ExprPath(..) => {
516             let def = self.tcx().def_map.borrow().get(&expr.id).unwrap().full_def();
517             self.cat_def(expr.id, expr.span, expr_ty, def)
518           }
519
520           ast::ExprParen(ref e) => {
521             self.cat_expr(&**e)
522           }
523
524           ast::ExprAddrOf(..) | ast::ExprCall(..) |
525           ast::ExprAssign(..) | ast::ExprAssignOp(..) |
526           ast::ExprClosure(..) | ast::ExprRet(..) |
527           ast::ExprUnary(..) | ast::ExprRange(..) |
528           ast::ExprMethodCall(..) | ast::ExprCast(..) |
529           ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
530           ast::ExprBinary(..) | ast::ExprWhile(..) |
531           ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
532           ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
533           ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
534           ast::ExprInlineAsm(..) | ast::ExprBox(..) => {
535             Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
536           }
537
538           ast::ExprIfLet(..) => {
539             self.tcx().sess.span_bug(expr.span, "non-desugared ExprIfLet");
540           }
541           ast::ExprWhileLet(..) => {
542             self.tcx().sess.span_bug(expr.span, "non-desugared ExprWhileLet");
543           }
544           ast::ExprForLoop(..) => {
545             self.tcx().sess.span_bug(expr.span, "non-desugared ExprForLoop");
546           }
547         }
548     }
549
550     pub fn cat_def(&self,
551                    id: ast::NodeId,
552                    span: Span,
553                    expr_ty: Ty<'tcx>,
554                    def: def::Def)
555                    -> McResult<cmt<'tcx>> {
556         debug!("cat_def: id={} expr={:?} def={:?}",
557                id, expr_ty, def);
558
559         match def {
560           def::DefStruct(..) | def::DefVariant(..) | def::DefConst(..) |
561           def::DefAssociatedConst(..) | def::DefFn(..) | def::DefMethod(..) => {
562                 Ok(self.cat_rvalue_node(id, span, expr_ty))
563           }
564           def::DefMod(_) | def::DefForeignMod(_) | def::DefUse(_) |
565           def::DefTrait(_) | def::DefTy(..) | def::DefPrimTy(_) |
566           def::DefTyParam(..) | def::DefRegion(_) |
567           def::DefLabel(_) | def::DefSelfTy(..) |
568           def::DefAssociatedTy(..) => {
569               Ok(Rc::new(cmt_ {
570                   id:id,
571                   span:span,
572                   cat:cat_static_item,
573                   mutbl: McImmutable,
574                   ty:expr_ty,
575                   note: NoteNone
576               }))
577           }
578
579           def::DefStatic(_, mutbl) => {
580               Ok(Rc::new(cmt_ {
581                   id:id,
582                   span:span,
583                   cat:cat_static_item,
584                   mutbl: if mutbl { McDeclared } else { McImmutable},
585                   ty:expr_ty,
586                   note: NoteNone
587               }))
588           }
589
590           def::DefUpvar(var_id, fn_node_id) => {
591               let ty = try!(self.node_ty(fn_node_id));
592               match ty.sty {
593                   ty::TyClosure(closure_id, _) => {
594                       match self.typer.closure_kind(closure_id) {
595                           Some(kind) => {
596                               self.cat_upvar(id, span, var_id, fn_node_id, kind)
597                           }
598                           None => {
599                               self.tcx().sess.span_bug(
600                                   span,
601                                   &*format!("No closure kind for {:?}", closure_id));
602                           }
603                       }
604                   }
605                   _ => {
606                       self.tcx().sess.span_bug(
607                           span,
608                           &format!("Upvar of non-closure {} - {:?}",
609                                   fn_node_id,
610                                   ty));
611                   }
612               }
613           }
614
615           def::DefLocal(vid) => {
616             Ok(Rc::new(cmt_ {
617                 id: id,
618                 span: span,
619                 cat: cat_local(vid),
620                 mutbl: MutabilityCategory::from_local(self.tcx(), vid),
621                 ty: expr_ty,
622                 note: NoteNone
623             }))
624           }
625         }
626     }
627
628     // Categorize an upvar, complete with invisible derefs of closure
629     // environment and upvar reference as appropriate.
630     fn cat_upvar(&self,
631                  id: ast::NodeId,
632                  span: Span,
633                  var_id: ast::NodeId,
634                  fn_node_id: ast::NodeId,
635                  kind: ty::ClosureKind)
636                  -> McResult<cmt<'tcx>>
637     {
638         // An upvar can have up to 3 components. We translate first to a
639         // `cat_upvar`, which is itself a fiction -- it represents the reference to the
640         // field from the environment.
641         //
642         // `cat_upvar`.  Next, we add a deref through the implicit
643         // environment pointer with an anonymous free region 'env and
644         // appropriate borrow kind for closure kinds that take self by
645         // reference.  Finally, if the upvar was captured
646         // by-reference, we add a deref through that reference.  The
647         // region of this reference is an inference variable 'up that
648         // was previously generated and recorded in the upvar borrow
649         // map.  The borrow kind bk is inferred by based on how the
650         // upvar is used.
651         //
652         // This results in the following table for concrete closure
653         // types:
654         //
655         //                | move                 | ref
656         // ---------------+----------------------+-------------------------------
657         // Fn             | copied -> &'env      | upvar -> &'env -> &'up bk
658         // FnMut          | copied -> &'env mut  | upvar -> &'env mut -> &'up bk
659         // FnOnce         | copied               | upvar -> &'up bk
660
661         let upvar_id = ty::UpvarId { var_id: var_id,
662                                      closure_expr_id: fn_node_id };
663         let var_ty = try!(self.node_ty(var_id));
664
665         // Mutability of original variable itself
666         let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
667
668         // Construct the upvar. This represents access to the field
669         // from the environment (perhaps we should eventually desugar
670         // this field further, but it will do for now).
671         let cmt_result = cmt_ {
672             id: id,
673             span: span,
674             cat: cat_upvar(Upvar {id: upvar_id, kind: kind}),
675             mutbl: var_mutbl,
676             ty: var_ty,
677             note: NoteNone
678         };
679
680         // If this is a `FnMut` or `Fn` closure, then the above is
681         // conceptually a `&mut` or `&` reference, so we have to add a
682         // deref.
683         let cmt_result = match kind {
684             ty::FnOnceClosureKind => {
685                 cmt_result
686             }
687             ty::FnMutClosureKind => {
688                 self.env_deref(id, span, upvar_id, var_mutbl, ty::MutBorrow, cmt_result)
689             }
690             ty::FnClosureKind => {
691                 self.env_deref(id, span, upvar_id, var_mutbl, ty::ImmBorrow, cmt_result)
692             }
693         };
694
695         // If this is a by-ref capture, then the upvar we loaded is
696         // actually a reference, so we have to add an implicit deref
697         // for that.
698         let upvar_id = ty::UpvarId { var_id: var_id,
699                                      closure_expr_id: fn_node_id };
700         let upvar_capture = self.typer.upvar_capture(upvar_id).unwrap();
701         let cmt_result = match upvar_capture {
702             ty::UpvarCapture::ByValue => {
703                 cmt_result
704             }
705             ty::UpvarCapture::ByRef(upvar_borrow) => {
706                 let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region);
707                 cmt_ {
708                     id: id,
709                     span: span,
710                     cat: cat_deref(Rc::new(cmt_result), 0, ptr),
711                     mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
712                     ty: var_ty,
713                     note: NoteUpvarRef(upvar_id)
714                 }
715             }
716         };
717
718         let ret = Rc::new(cmt_result);
719         debug!("cat_upvar ret={:?}", ret);
720         Ok(ret)
721     }
722
723     fn env_deref(&self,
724                  id: ast::NodeId,
725                  span: Span,
726                  upvar_id: ty::UpvarId,
727                  upvar_mutbl: MutabilityCategory,
728                  env_borrow_kind: ty::BorrowKind,
729                  cmt_result: cmt_<'tcx>)
730                  -> cmt_<'tcx>
731     {
732         // Look up the node ID of the closure body so we can construct
733         // a free region within it
734         let fn_body_id = {
735             let fn_expr = match self.tcx().map.find(upvar_id.closure_expr_id) {
736                 Some(ast_map::NodeExpr(e)) => e,
737                 _ => unreachable!()
738             };
739
740             match fn_expr.node {
741                 ast::ExprClosure(_, _, ref body) => body.id,
742                 _ => unreachable!()
743             }
744         };
745
746         // Region of environment pointer
747         let env_region = ty::ReFree(ty::FreeRegion {
748             // The environment of a closure is guaranteed to
749             // outlive any bindings introduced in the body of the
750             // closure itself.
751             scope: region::DestructionScopeData::new(fn_body_id),
752             bound_region: ty::BrEnv
753         });
754
755         let env_ptr = BorrowedPtr(env_borrow_kind, env_region);
756
757         let var_ty = cmt_result.ty;
758
759         // We need to add the env deref.  This means
760         // that the above is actually immutable and
761         // has a ref type.  However, nothing should
762         // actually look at the type, so we can get
763         // away with stuffing a `TyError` in there
764         // instead of bothering to construct a proper
765         // one.
766         let cmt_result = cmt_ {
767             mutbl: McImmutable,
768             ty: self.tcx().types.err,
769             ..cmt_result
770         };
771
772         let mut deref_mutbl = MutabilityCategory::from_borrow_kind(env_borrow_kind);
773
774         // Issue #18335. If variable is declared as immutable, override the
775         // mutability from the environment and substitute an `&T` anyway.
776         match upvar_mutbl {
777             McImmutable => { deref_mutbl = McImmutable; }
778             McDeclared | McInherited => { }
779         }
780
781         let ret = cmt_ {
782             id: id,
783             span: span,
784             cat: cat_deref(Rc::new(cmt_result), 0, env_ptr),
785             mutbl: deref_mutbl,
786             ty: var_ty,
787             note: NoteClosureEnv(upvar_id)
788         };
789
790         debug!("env_deref ret {:?}", ret);
791
792         ret
793     }
794
795     /// Returns the lifetime of a temporary created by expr with id `id`.
796     /// This could be `'static` if `id` is part of a constant expression.
797     pub fn temporary_scope(&self, id: ast::NodeId) -> ty::Region {
798         match self.typer.temporary_scope(id) {
799             Some(scope) => ty::ReScope(scope),
800             None => ty::ReStatic
801         }
802     }
803
804     pub fn cat_rvalue_node(&self,
805                            id: ast::NodeId,
806                            span: Span,
807                            expr_ty: Ty<'tcx>)
808                            -> cmt<'tcx> {
809         let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
810                                .unwrap_or(check_const::ConstQualif::NOT_CONST);
811
812         // Only promote `[T; 0]` before an RFC for rvalue promotions
813         // is accepted.
814         let qualif = match expr_ty.sty {
815             ty::TyArray(_, 0) => qualif,
816             _ => check_const::ConstQualif::NOT_CONST
817         };
818
819         // Compute maximum lifetime of this rvalue. This is 'static if
820         // we can promote to a constant, otherwise equal to enclosing temp
821         // lifetime.
822         let re = if qualif.intersects(check_const::ConstQualif::NON_STATIC_BORROWS) {
823             self.temporary_scope(id)
824         } else {
825             ty::ReStatic
826         };
827         let ret = self.cat_rvalue(id, span, re, expr_ty);
828         debug!("cat_rvalue_node ret {:?}", ret);
829         ret
830     }
831
832     pub fn cat_rvalue(&self,
833                       cmt_id: ast::NodeId,
834                       span: Span,
835                       temp_scope: ty::Region,
836                       expr_ty: Ty<'tcx>) -> cmt<'tcx> {
837         let ret = Rc::new(cmt_ {
838             id:cmt_id,
839             span:span,
840             cat:cat_rvalue(temp_scope),
841             mutbl:McDeclared,
842             ty:expr_ty,
843             note: NoteNone
844         });
845         debug!("cat_rvalue ret {:?}", ret);
846         ret
847     }
848
849     pub fn cat_field<N:ast_node>(&self,
850                                  node: &N,
851                                  base_cmt: cmt<'tcx>,
852                                  f_name: ast::Name,
853                                  f_ty: Ty<'tcx>)
854                                  -> cmt<'tcx> {
855         let ret = Rc::new(cmt_ {
856             id: node.id(),
857             span: node.span(),
858             mutbl: base_cmt.mutbl.inherit(),
859             cat: cat_interior(base_cmt, InteriorField(NamedField(f_name))),
860             ty: f_ty,
861             note: NoteNone
862         });
863         debug!("cat_field ret {:?}", ret);
864         ret
865     }
866
867     pub fn cat_tup_field<N:ast_node>(&self,
868                                      node: &N,
869                                      base_cmt: cmt<'tcx>,
870                                      f_idx: usize,
871                                      f_ty: Ty<'tcx>)
872                                      -> cmt<'tcx> {
873         let ret = Rc::new(cmt_ {
874             id: node.id(),
875             span: node.span(),
876             mutbl: base_cmt.mutbl.inherit(),
877             cat: cat_interior(base_cmt, InteriorField(PositionalField(f_idx))),
878             ty: f_ty,
879             note: NoteNone
880         });
881         debug!("cat_tup_field ret {:?}", ret);
882         ret
883     }
884
885     fn cat_deref<N:ast_node>(&self,
886                              node: &N,
887                              base_cmt: cmt<'tcx>,
888                              deref_cnt: usize,
889                              deref_context: DerefKindContext)
890                              -> McResult<cmt<'tcx>> {
891         let method_call = ty::MethodCall {
892             expr_id: node.id(),
893             autoderef: deref_cnt as u32
894         };
895         let method_ty = self.typer.node_method_ty(method_call);
896
897         debug!("cat_deref: method_call={:?} method_ty={:?}",
898                method_call, method_ty.map(|ty| ty));
899
900         let base_cmt = match method_ty {
901             Some(method_ty) => {
902                 let ref_ty =
903                     self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap().unwrap();
904                 self.cat_rvalue_node(node.id(), node.span(), ref_ty)
905             }
906             None => base_cmt
907         };
908         let base_cmt_ty = base_cmt.ty;
909         match base_cmt_ty.builtin_deref(true) {
910             Some(mt) => {
911                 let ret = self.cat_deref_common(node, base_cmt, deref_cnt,
912                                               mt.ty,
913                                               deref_context,
914                                                 /* implicit: */ false);
915                 debug!("cat_deref ret {:?}", ret);
916                 ret
917             }
918             None => {
919                 debug!("Explicit deref of non-derefable type: {:?}",
920                        base_cmt_ty);
921                 return Err(());
922             }
923         }
924     }
925
926     fn cat_deref_common<N:ast_node>(&self,
927                                     node: &N,
928                                     base_cmt: cmt<'tcx>,
929                                     deref_cnt: usize,
930                                     deref_ty: Ty<'tcx>,
931                                     deref_context: DerefKindContext,
932                                     implicit: bool)
933                                     -> McResult<cmt<'tcx>>
934     {
935         let (m, cat) = match try!(deref_kind(base_cmt.ty, deref_context)) {
936             deref_ptr(ptr) => {
937                 let ptr = if implicit {
938                     match ptr {
939                         BorrowedPtr(bk, r) => Implicit(bk, r),
940                         _ => self.tcx().sess.span_bug(node.span(),
941                             "Implicit deref of non-borrowed pointer")
942                     }
943                 } else {
944                     ptr
945                 };
946                 // for unique ptrs, we inherit mutability from the
947                 // owning reference.
948                 (MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
949                  cat_deref(base_cmt, deref_cnt, ptr))
950             }
951             deref_interior(interior) => {
952                 (base_cmt.mutbl.inherit(), cat_interior(base_cmt, interior))
953             }
954         };
955         let ret = Rc::new(cmt_ {
956             id: node.id(),
957             span: node.span(),
958             cat: cat,
959             mutbl: m,
960             ty: deref_ty,
961             note: NoteNone
962         });
963         debug!("cat_deref_common ret {:?}", ret);
964         Ok(ret)
965     }
966
967     pub fn cat_index<N:ast_node>(&self,
968                                  elt: &N,
969                                  mut base_cmt: cmt<'tcx>,
970                                  context: InteriorOffsetKind)
971                                  -> McResult<cmt<'tcx>> {
972         //! Creates a cmt for an indexing operation (`[]`).
973         //!
974         //! One subtle aspect of indexing that may not be
975         //! immediately obvious: for anything other than a fixed-length
976         //! vector, an operation like `x[y]` actually consists of two
977         //! disjoint (from the point of view of borrowck) operations.
978         //! The first is a deref of `x` to create a pointer `p` that points
979         //! at the first element in the array. The second operation is
980         //! an index which adds `y*sizeof(T)` to `p` to obtain the
981         //! pointer to `x[y]`. `cat_index` will produce a resulting
982         //! cmt containing both this deref and the indexing,
983         //! presuming that `base_cmt` is not of fixed-length type.
984         //!
985         //! # Parameters
986         //! - `elt`: the AST node being indexed
987         //! - `base_cmt`: the cmt of `elt`
988
989         let method_call = ty::MethodCall::expr(elt.id());
990         let method_ty = self.typer.node_method_ty(method_call);
991
992         let element_ty = match method_ty {
993             Some(method_ty) => {
994                 let ref_ty = self.overloaded_method_return_ty(method_ty);
995                 base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
996
997                 // FIXME(#20649) -- why are we using the `self_ty` as the element type...?
998                 let self_ty = method_ty.fn_sig().input(0);
999                 self.tcx().no_late_bound_regions(&self_ty).unwrap()
1000             }
1001             None => {
1002                 match base_cmt.ty.builtin_index() {
1003                     Some(ty) => ty,
1004                     None => {
1005                         return Err(());
1006                     }
1007                 }
1008             }
1009         };
1010
1011         let m = base_cmt.mutbl.inherit();
1012         let ret = interior(elt, base_cmt.clone(), base_cmt.ty,
1013                            m, context, element_ty);
1014         debug!("cat_index ret {:?}", ret);
1015         return Ok(ret);
1016
1017         fn interior<'tcx, N: ast_node>(elt: &N,
1018                                        of_cmt: cmt<'tcx>,
1019                                        vec_ty: Ty<'tcx>,
1020                                        mutbl: MutabilityCategory,
1021                                        context: InteriorOffsetKind,
1022                                        element_ty: Ty<'tcx>) -> cmt<'tcx>
1023         {
1024             let interior_elem = InteriorElement(context, element_kind(vec_ty));
1025             Rc::new(cmt_ {
1026                 id:elt.id(),
1027                 span:elt.span(),
1028                 cat:cat_interior(of_cmt, interior_elem),
1029                 mutbl:mutbl,
1030                 ty:element_ty,
1031                 note: NoteNone
1032             })
1033         }
1034     }
1035
1036     // Takes either a vec or a reference to a vec and returns the cmt for the
1037     // underlying vec.
1038     fn deref_vec<N:ast_node>(&self,
1039                              elt: &N,
1040                              base_cmt: cmt<'tcx>,
1041                              context: InteriorOffsetKind)
1042                              -> McResult<cmt<'tcx>>
1043     {
1044         let ret = match try!(deref_kind(base_cmt.ty, Some(context))) {
1045             deref_ptr(ptr) => {
1046                 // for unique ptrs, we inherit mutability from the
1047                 // owning reference.
1048                 let m = MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr);
1049
1050                 // the deref is explicit in the resulting cmt
1051                 Rc::new(cmt_ {
1052                     id:elt.id(),
1053                     span:elt.span(),
1054                     cat:cat_deref(base_cmt.clone(), 0, ptr),
1055                     mutbl:m,
1056                     ty: match base_cmt.ty.builtin_deref(false) {
1057                         Some(mt) => mt.ty,
1058                         None => self.tcx().sess.bug("Found non-derefable type")
1059                     },
1060                     note: NoteNone
1061                 })
1062             }
1063
1064             deref_interior(_) => {
1065                 base_cmt
1066             }
1067         };
1068         debug!("deref_vec ret {:?}", ret);
1069         Ok(ret)
1070     }
1071
1072     /// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is
1073     /// the pattern `Q`, returns:
1074     ///
1075     /// * a cmt for `Q`
1076     /// * the mutability and region of the slice `Q`
1077     ///
1078     /// These last two bits of info happen to be things that borrowck needs.
1079     pub fn cat_slice_pattern(&self,
1080                              vec_cmt: cmt<'tcx>,
1081                              slice_pat: &ast::Pat)
1082                              -> McResult<(cmt<'tcx>, ast::Mutability, ty::Region)> {
1083         let slice_ty = try!(self.node_ty(slice_pat.id));
1084         let (slice_mutbl, slice_r) = vec_slice_info(self.tcx(),
1085                                                     slice_pat,
1086                                                     slice_ty);
1087         let context = InteriorOffsetKind::Pattern;
1088         let cmt_vec = try!(self.deref_vec(slice_pat, vec_cmt, context));
1089         let cmt_slice = try!(self.cat_index(slice_pat, cmt_vec, context));
1090         return Ok((cmt_slice, slice_mutbl, slice_r));
1091
1092         /// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
1093         /// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
1094         /// have to recurse through rptrs.
1095         fn vec_slice_info(tcx: &ty::ctxt,
1096                           pat: &ast::Pat,
1097                           slice_ty: Ty)
1098                           -> (ast::Mutability, ty::Region) {
1099             match slice_ty.sty {
1100                 ty::TyRef(r, ref mt) => match mt.ty.sty {
1101                     ty::TySlice(_) => (mt.mutbl, *r),
1102                     _ => vec_slice_info(tcx, pat, mt.ty),
1103                 },
1104
1105                 _ => {
1106                     tcx.sess.span_bug(pat.span,
1107                                       "type of slice pattern is not a slice");
1108                 }
1109             }
1110         }
1111     }
1112
1113     pub fn cat_imm_interior<N:ast_node>(&self,
1114                                         node: &N,
1115                                         base_cmt: cmt<'tcx>,
1116                                         interior_ty: Ty<'tcx>,
1117                                         interior: InteriorKind)
1118                                         -> cmt<'tcx> {
1119         let ret = Rc::new(cmt_ {
1120             id: node.id(),
1121             span: node.span(),
1122             mutbl: base_cmt.mutbl.inherit(),
1123             cat: cat_interior(base_cmt, interior),
1124             ty: interior_ty,
1125             note: NoteNone
1126         });
1127         debug!("cat_imm_interior ret={:?}", ret);
1128         ret
1129     }
1130
1131     pub fn cat_downcast<N:ast_node>(&self,
1132                                     node: &N,
1133                                     base_cmt: cmt<'tcx>,
1134                                     downcast_ty: Ty<'tcx>,
1135                                     variant_did: ast::DefId)
1136                                     -> cmt<'tcx> {
1137         let ret = Rc::new(cmt_ {
1138             id: node.id(),
1139             span: node.span(),
1140             mutbl: base_cmt.mutbl.inherit(),
1141             cat: cat_downcast(base_cmt, variant_did),
1142             ty: downcast_ty,
1143             note: NoteNone
1144         });
1145         debug!("cat_downcast ret={:?}", ret);
1146         ret
1147     }
1148
1149     pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, mut op: F) -> McResult<()>
1150         where F: FnMut(&MemCategorizationContext<'t, 'a, 'tcx>, cmt<'tcx>, &ast::Pat),
1151     {
1152         self.cat_pattern_(cmt, pat, &mut op)
1153     }
1154
1155     // FIXME(#19596) This is a workaround, but there should be a better way to do this
1156     fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &ast::Pat, op: &mut F)
1157                        -> McResult<()>
1158         where F : FnMut(&MemCategorizationContext<'t, 'a, 'tcx>, cmt<'tcx>, &ast::Pat),
1159     {
1160         // Here, `cmt` is the categorization for the value being
1161         // matched and pat is the pattern it is being matched against.
1162         //
1163         // In general, the way that this works is that we walk down
1164         // the pattern, constructing a cmt that represents the path
1165         // that will be taken to reach the value being matched.
1166         //
1167         // When we encounter named bindings, we take the cmt that has
1168         // been built up and pass it off to guarantee_valid() so that
1169         // we can be sure that the binding will remain valid for the
1170         // duration of the arm.
1171         //
1172         // (*2) There is subtlety concerning the correspondence between
1173         // pattern ids and types as compared to *expression* ids and
1174         // types. This is explained briefly. on the definition of the
1175         // type `cmt`, so go off and read what it says there, then
1176         // come back and I'll dive into a bit more detail here. :) OK,
1177         // back?
1178         //
1179         // In general, the id of the cmt should be the node that
1180         // "produces" the value---patterns aren't executable code
1181         // exactly, but I consider them to "execute" when they match a
1182         // value, and I consider them to produce the value that was
1183         // matched. So if you have something like:
1184         //
1185         //     let x = @@3;
1186         //     match x {
1187         //       @@y { ... }
1188         //     }
1189         //
1190         // In this case, the cmt and the relevant ids would be:
1191         //
1192         //     CMT             Id                  Type of Id Type of cmt
1193         //
1194         //     local(x)->@->@
1195         //     ^~~~~~~^        `x` from discr      @@int      @@int
1196         //     ^~~~~~~~~~^     `@@y` pattern node  @@int      @int
1197         //     ^~~~~~~~~~~~~^  `@y` pattern node   @int       int
1198         //
1199         // You can see that the types of the id and the cmt are in
1200         // sync in the first line, because that id is actually the id
1201         // of an expression. But once we get to pattern ids, the types
1202         // step out of sync again. So you'll see below that we always
1203         // get the type of the *subpattern* and use that.
1204
1205         debug!("cat_pattern: {:?} cmt={:?}",
1206                pat,
1207                cmt);
1208
1209         (*op)(self, cmt.clone(), pat);
1210
1211         let opt_def = self.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def());
1212
1213         // Note: This goes up here (rather than within the PatEnum arm
1214         // alone) because struct patterns can refer to struct types or
1215         // to struct variants within enums.
1216         let cmt = match opt_def {
1217             Some(def::DefVariant(enum_did, variant_did, _))
1218                 // univariant enums do not need downcasts
1219                 if !self.tcx().lookup_adt_def(enum_did).is_univariant() => {
1220                     self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
1221                 }
1222             _ => cmt
1223         };
1224
1225         match pat.node {
1226           ast::PatWild(_) => {
1227             // _
1228           }
1229
1230           ast::PatEnum(_, None) => {
1231             // variant(..)
1232           }
1233           ast::PatEnum(_, Some(ref subpats)) => {
1234             match opt_def {
1235                 Some(def::DefVariant(..)) => {
1236                     // variant(x, y, z)
1237                     for (i, subpat) in subpats.iter().enumerate() {
1238                         let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
1239
1240                         let subcmt =
1241                             self.cat_imm_interior(
1242                                 pat, cmt.clone(), subpat_ty,
1243                                 InteriorField(PositionalField(i)));
1244
1245                         try!(self.cat_pattern_(subcmt, &**subpat, op));
1246                     }
1247                 }
1248                 Some(def::DefStruct(..)) => {
1249                     for (i, subpat) in subpats.iter().enumerate() {
1250                         let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
1251                         let cmt_field =
1252                             self.cat_imm_interior(
1253                                 pat, cmt.clone(), subpat_ty,
1254                                 InteriorField(PositionalField(i)));
1255                         try!(self.cat_pattern_(cmt_field, &**subpat, op));
1256                     }
1257                 }
1258                 Some(def::DefConst(..)) | Some(def::DefAssociatedConst(..)) => {
1259                     for subpat in subpats {
1260                         try!(self.cat_pattern_(cmt.clone(), &**subpat, op));
1261                     }
1262                 }
1263                 _ => {
1264                     self.tcx().sess.span_bug(
1265                         pat.span,
1266                         "enum pattern didn't resolve to enum or struct");
1267                 }
1268             }
1269           }
1270
1271           ast::PatQPath(..) => {
1272               // Lone constant: ignore
1273           }
1274
1275           ast::PatIdent(_, _, Some(ref subpat)) => {
1276               try!(self.cat_pattern_(cmt, &**subpat, op));
1277           }
1278
1279           ast::PatIdent(_, _, None) => {
1280               // nullary variant or identifier: ignore
1281           }
1282
1283           ast::PatStruct(_, ref field_pats, _) => {
1284             // {f1: p1, ..., fN: pN}
1285             for fp in field_pats {
1286                 let field_ty = try!(self.pat_ty(&*fp.node.pat)); // see (*2)
1287                 let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.ident.name, field_ty);
1288                 try!(self.cat_pattern_(cmt_field, &*fp.node.pat, op));
1289             }
1290           }
1291
1292           ast::PatTup(ref subpats) => {
1293             // (p1, ..., pN)
1294             for (i, subpat) in subpats.iter().enumerate() {
1295                 let subpat_ty = try!(self.pat_ty(&**subpat)); // see (*2)
1296                 let subcmt =
1297                     self.cat_imm_interior(
1298                         pat, cmt.clone(), subpat_ty,
1299                         InteriorField(PositionalField(i)));
1300                 try!(self.cat_pattern_(subcmt, &**subpat, op));
1301             }
1302           }
1303
1304           ast::PatBox(ref subpat) | ast::PatRegion(ref subpat, _) => {
1305             // box p1, &p1, &mut p1.  we can ignore the mutability of
1306             // PatRegion since that information is already contained
1307             // in the type.
1308             let subcmt = try!(self.cat_deref(pat, cmt, 0, None));
1309               try!(self.cat_pattern_(subcmt, &**subpat, op));
1310           }
1311
1312           ast::PatVec(ref before, ref slice, ref after) => {
1313               let context = InteriorOffsetKind::Pattern;
1314               let vec_cmt = try!(self.deref_vec(pat, cmt, context));
1315               let elt_cmt = try!(self.cat_index(pat, vec_cmt, context));
1316               for before_pat in before {
1317                   try!(self.cat_pattern_(elt_cmt.clone(), &**before_pat, op));
1318               }
1319               if let Some(ref slice_pat) = *slice {
1320                   let slice_ty = try!(self.pat_ty(&**slice_pat));
1321                   let slice_cmt = self.cat_rvalue_node(pat.id(), pat.span(), slice_ty);
1322                   try!(self.cat_pattern_(slice_cmt, &**slice_pat, op));
1323               }
1324               for after_pat in after {
1325                   try!(self.cat_pattern_(elt_cmt.clone(), &**after_pat, op));
1326               }
1327           }
1328
1329           ast::PatLit(_) | ast::PatRange(_, _) => {
1330               /*always ok*/
1331           }
1332
1333           ast::PatMac(_) => {
1334               self.tcx().sess.span_bug(pat.span, "unexpanded macro");
1335           }
1336         }
1337
1338         Ok(())
1339     }
1340
1341     fn overloaded_method_return_ty(&self,
1342                                    method_ty: Ty<'tcx>)
1343                                    -> Ty<'tcx>
1344     {
1345         // When we process an overloaded `*` or `[]` etc, we often
1346         // need to extract the return type of the method. These method
1347         // types are generated by method resolution and always have
1348         // all late-bound regions fully instantiated, so we just want
1349         // to skip past the binder.
1350         self.tcx().no_late_bound_regions(&method_ty.fn_ret())
1351            .unwrap()
1352            .unwrap() // overloaded ops do not diverge, either
1353     }
1354 }
1355
1356 #[derive(Clone, Debug)]
1357 pub enum Aliasability {
1358     FreelyAliasable(AliasableReason),
1359     NonAliasable,
1360     ImmutableUnique(Box<Aliasability>),
1361 }
1362
1363 #[derive(Copy, Clone, Debug)]
1364 pub enum AliasableReason {
1365     AliasableBorrowed,
1366     AliasableClosure(ast::NodeId), // Aliasable due to capture Fn closure env
1367     AliasableOther,
1368     UnaliasableImmutable, // Created as needed upon seeing ImmutableUnique
1369     AliasableStatic,
1370     AliasableStaticMut,
1371 }
1372
1373 impl<'tcx> cmt_<'tcx> {
1374     pub fn guarantor(&self) -> cmt<'tcx> {
1375         //! Returns `self` after stripping away any derefs or
1376         //! interior content. The return value is basically the `cmt` which
1377         //! determines how long the value in `self` remains live.
1378
1379         match self.cat {
1380             cat_rvalue(..) |
1381             cat_static_item |
1382             cat_local(..) |
1383             cat_deref(_, _, UnsafePtr(..)) |
1384             cat_deref(_, _, BorrowedPtr(..)) |
1385             cat_deref(_, _, Implicit(..)) |
1386             cat_upvar(..) => {
1387                 Rc::new((*self).clone())
1388             }
1389             cat_downcast(ref b, _) |
1390             cat_interior(ref b, _) |
1391             cat_deref(ref b, _, Unique) => {
1392                 b.guarantor()
1393             }
1394         }
1395     }
1396
1397     /// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
1398     pub fn freely_aliasable(&self, ctxt: &ty::ctxt<'tcx>)
1399                             -> Aliasability {
1400         // Maybe non-obvious: copied upvars can only be considered
1401         // non-aliasable in once closures, since any other kind can be
1402         // aliased and eventually recused.
1403
1404         match self.cat {
1405             cat_deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) |
1406             cat_deref(ref b, _, Implicit(ty::MutBorrow, _)) |
1407             cat_deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
1408             cat_deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
1409             cat_downcast(ref b, _) |
1410             cat_interior(ref b, _) => {
1411                 // Aliasability depends on base cmt
1412                 b.freely_aliasable(ctxt)
1413             }
1414
1415             cat_deref(ref b, _, Unique) => {
1416                 let sub = b.freely_aliasable(ctxt);
1417                 if b.mutbl.is_mutable() {
1418                     // Aliasability depends on base cmt alone
1419                     sub
1420                 } else {
1421                     // Do not allow mutation through an immutable box.
1422                     ImmutableUnique(Box::new(sub))
1423                 }
1424             }
1425
1426             cat_rvalue(..) |
1427             cat_local(..) |
1428             cat_upvar(..) |
1429             cat_deref(_, _, UnsafePtr(..)) => { // yes, it's aliasable, but...
1430                 NonAliasable
1431             }
1432
1433             cat_static_item(..) => {
1434                 if self.mutbl.is_mutable() {
1435                     FreelyAliasable(AliasableStaticMut)
1436                 } else {
1437                     FreelyAliasable(AliasableStatic)
1438                 }
1439             }
1440
1441             cat_deref(ref base, _, BorrowedPtr(ty::ImmBorrow, _)) |
1442             cat_deref(ref base, _, Implicit(ty::ImmBorrow, _)) => {
1443                 match base.cat {
1444                     cat_upvar(Upvar{ id, .. }) =>
1445                         FreelyAliasable(AliasableClosure(id.closure_expr_id)),
1446                     _ => FreelyAliasable(AliasableBorrowed)
1447                 }
1448             }
1449         }
1450     }
1451
1452     // Digs down through one or two layers of deref and grabs the cmt
1453     // for the upvar if a note indicates there is one.
1454     pub fn upvar(&self) -> Option<cmt<'tcx>> {
1455         match self.note {
1456             NoteClosureEnv(..) | NoteUpvarRef(..) => {
1457                 Some(match self.cat {
1458                     cat_deref(ref inner, _, _) => {
1459                         match inner.cat {
1460                             cat_deref(ref inner, _, _) => inner.clone(),
1461                             cat_upvar(..) => inner.clone(),
1462                             _ => unreachable!()
1463                         }
1464                     }
1465                     _ => unreachable!()
1466                 })
1467             }
1468             NoteNone => None
1469         }
1470     }
1471
1472
1473     pub fn descriptive_string(&self, tcx: &ty::ctxt) -> String {
1474         match self.cat {
1475             cat_static_item => {
1476                 "static item".to_string()
1477             }
1478             cat_rvalue(..) => {
1479                 "non-lvalue".to_string()
1480             }
1481             cat_local(vid) => {
1482                 match tcx.map.find(vid) {
1483                     Some(ast_map::NodeArg(_)) => {
1484                         "argument".to_string()
1485                     }
1486                     _ => "local variable".to_string()
1487                 }
1488             }
1489             cat_deref(_, _, pk) => {
1490                 let upvar = self.upvar();
1491                 match upvar.as_ref().map(|i| &i.cat) {
1492                     Some(&cat_upvar(ref var)) => {
1493                         var.to_string()
1494                     }
1495                     Some(_) => unreachable!(),
1496                     None => {
1497                         match pk {
1498                             Implicit(..) => {
1499                                 format!("indexed content")
1500                             }
1501                             Unique => {
1502                                 format!("`Box` content")
1503                             }
1504                             UnsafePtr(..) => {
1505                                 format!("dereference of raw pointer")
1506                             }
1507                             BorrowedPtr(..) => {
1508                                 format!("borrowed content")
1509                             }
1510                         }
1511                     }
1512                 }
1513             }
1514             cat_interior(_, InteriorField(NamedField(_))) => {
1515                 "field".to_string()
1516             }
1517             cat_interior(_, InteriorField(PositionalField(_))) => {
1518                 "anonymous field".to_string()
1519             }
1520             cat_interior(_, InteriorElement(InteriorOffsetKind::Index,
1521                                             VecElement)) |
1522             cat_interior(_, InteriorElement(InteriorOffsetKind::Index,
1523                                             OtherElement)) => {
1524                 "indexed content".to_string()
1525             }
1526             cat_interior(_, InteriorElement(InteriorOffsetKind::Pattern,
1527                                             VecElement)) |
1528             cat_interior(_, InteriorElement(InteriorOffsetKind::Pattern,
1529                                             OtherElement)) => {
1530                 "pattern-bound indexed content".to_string()
1531             }
1532             cat_upvar(ref var) => {
1533                 var.to_string()
1534             }
1535             cat_downcast(ref cmt, _) => {
1536                 cmt.descriptive_string(tcx)
1537             }
1538         }
1539     }
1540 }
1541
1542 impl<'tcx> fmt::Debug for cmt_<'tcx> {
1543     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1544         write!(f, "{{{:?} id:{} m:{:?} ty:{:?}}}",
1545                self.cat,
1546                self.id,
1547                self.mutbl,
1548                self.ty)
1549     }
1550 }
1551
1552 impl<'tcx> fmt::Debug for categorization<'tcx> {
1553     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1554         match *self {
1555             cat_static_item => write!(f, "static"),
1556             cat_rvalue(r) => write!(f, "rvalue({:?})", r),
1557             cat_local(id) => {
1558                let name = ty::tls::with(|tcx| tcx.local_var_name_str(id));
1559                write!(f, "local({})", name)
1560             }
1561             cat_upvar(upvar) => {
1562                 write!(f, "upvar({:?})", upvar)
1563             }
1564             cat_deref(ref cmt, derefs, ptr) => {
1565                 write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs)
1566             }
1567             cat_interior(ref cmt, interior) => {
1568                 write!(f, "{:?}.{:?}", cmt.cat, interior)
1569             }
1570             cat_downcast(ref cmt, _) => {
1571                 write!(f, "{:?}->(enum)", cmt.cat)
1572             }
1573         }
1574     }
1575 }
1576
1577 pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
1578     match ptr {
1579         Unique => "Box",
1580         BorrowedPtr(ty::ImmBorrow, _) |
1581         Implicit(ty::ImmBorrow, _) => "&",
1582         BorrowedPtr(ty::MutBorrow, _) |
1583         Implicit(ty::MutBorrow, _) => "&mut",
1584         BorrowedPtr(ty::UniqueImmBorrow, _) |
1585         Implicit(ty::UniqueImmBorrow, _) => "&unique",
1586         UnsafePtr(_) => "*",
1587     }
1588 }
1589
1590 impl fmt::Debug for PointerKind {
1591     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1592         match *self {
1593             Unique => write!(f, "Box"),
1594             BorrowedPtr(ty::ImmBorrow, ref r) |
1595             Implicit(ty::ImmBorrow, ref r) => {
1596                 write!(f, "&{:?}", r)
1597             }
1598             BorrowedPtr(ty::MutBorrow, ref r) |
1599             Implicit(ty::MutBorrow, ref r) => {
1600                 write!(f, "&{:?} mut", r)
1601             }
1602             BorrowedPtr(ty::UniqueImmBorrow, ref r) |
1603             Implicit(ty::UniqueImmBorrow, ref r) => {
1604                 write!(f, "&{:?} uniq", r)
1605             }
1606             UnsafePtr(_) => write!(f, "*")
1607         }
1608     }
1609 }
1610
1611 impl fmt::Debug for InteriorKind {
1612     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1613         match *self {
1614             InteriorField(NamedField(fld)) => write!(f, "{}", fld),
1615             InteriorField(PositionalField(i)) => write!(f, "#{}", i),
1616             InteriorElement(..) => write!(f, "[]"),
1617         }
1618     }
1619 }
1620
1621 fn element_kind(t: Ty) -> ElementKind {
1622     match t.sty {
1623         ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
1624         ty::TyBox(ty) => match ty.sty {
1625             ty::TySlice(_) => VecElement,
1626             _ => OtherElement
1627         },
1628         ty::TyArray(..) | ty::TySlice(_) => VecElement,
1629         _ => OtherElement
1630     }
1631 }
1632
1633 impl fmt::Debug for Upvar {
1634     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1635         write!(f, "{:?}/{:?}", self.id, self.kind)
1636     }
1637 }
1638
1639 impl fmt::Display for Upvar {
1640     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1641         let kind = match self.kind {
1642             ty::FnClosureKind => "Fn",
1643             ty::FnMutClosureKind => "FnMut",
1644             ty::FnOnceClosureKind => "FnOnce",
1645         };
1646         write!(f, "captured outer variable in an `{}` closure", kind)
1647     }
1648 }