]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/mem_categorization.rs
librustc: Implement coercion for traits.
[rust.git] / src / librustc / middle / mem_categorization.rs
1 // Copyright 2012-2013 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 /*!
12  * # Categorization
13  *
14  * The job of the categorization module is to analyze an expression to
15  * determine what kind of memory is used in evaluating it (for example,
16  * where dereferences occur and what kind of pointer is dereferenced;
17  * whether the memory is mutable; etc)
18  *
19  * Categorization effectively transforms all of our expressions into
20  * expressions of the following forms (the actual enum has many more
21  * possibilities, naturally, but they are all variants of these base
22  * forms):
23  *
24  *     E = rvalue    // some computed rvalue
25  *       | x         // address of a local variable, arg, or upvar
26  *       | *E        // deref of a ptr
27  *       | E.comp    // access to an interior component
28  *
29  * Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
30  * address where the result is to be found.  If Expr is an lvalue, then this
31  * is the address of the lvalue.  If Expr is an rvalue, this is the address of
32  * some temporary spot in memory where the result is stored.
33  *
34  * Now, cat_expr() classies the expression Expr and the address A=ToAddr(Expr)
35  * as follows:
36  *
37  * - cat: what kind of expression was this?  This is a subset of the
38  *   full expression forms which only includes those that we care about
39  *   for the purpose of the analysis.
40  * - mutbl: mutability of the address A
41  * - ty: the type of data found at the address A
42  *
43  * The resulting categorization tree differs somewhat from the expressions
44  * themselves.  For example, auto-derefs are explicit.  Also, an index a[b] is
45  * decomposed into two operations: a derefence to reach the array data and
46  * then an index to jump forward to the relevant item.
47  */
48
49
50 use middle::ty;
51 use middle::typeck;
52 use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
53 use util::common::indenter;
54
55 use syntax::ast::{MutImmutable, MutMutable};
56 use syntax::ast;
57 use syntax::codemap::Span;
58 use syntax::print::pprust;
59 use syntax::parse::token;
60
61 #[deriving(Eq)]
62 pub enum categorization {
63     cat_rvalue(ast::NodeId),           // temporary val, argument is its scope
64     cat_static_item,
65     cat_copied_upvar(CopiedUpvar),     // upvar copied into @fn or ~fn env
66     cat_stack_upvar(cmt),              // by ref upvar from ||
67     cat_local(ast::NodeId),            // local variable
68     cat_arg(ast::NodeId),              // formal argument
69     cat_deref(cmt, uint, PointerKind), // deref of a ptr
70     cat_interior(cmt, InteriorKind),   // something interior: field, tuple, etc
71     cat_downcast(cmt),                 // selects a particular enum variant (..)
72     cat_discr(cmt, ast::NodeId),       // match discriminant (see preserve())
73     cat_self(ast::NodeId),             // explicit `self`
74
75     // (..) downcast is only required if the enum has more than one variant
76 }
77
78 #[deriving(Eq)]
79 pub struct CopiedUpvar {
80     upvar_id: ast::NodeId,
81     onceness: ast::Onceness,
82 }
83
84 // different kinds of pointers:
85 #[deriving(Eq, IterBytes)]
86 pub enum PointerKind {
87     uniq_ptr,
88     gc_ptr(ast::Mutability),
89     region_ptr(ast::Mutability, ty::Region),
90     unsafe_ptr(ast::Mutability)
91 }
92
93 // We use the term "interior" to mean "something reachable from the
94 // base without a pointer dereference", e.g. a field
95 #[deriving(Eq, IterBytes)]
96 pub enum InteriorKind {
97     InteriorField(FieldName),
98     InteriorElement(ElementKind),
99 }
100
101 #[deriving(Eq, IterBytes)]
102 pub enum FieldName {
103     NamedField(ast::Name),
104     PositionalField(uint)
105 }
106
107 #[deriving(Eq, IterBytes)]
108 pub enum ElementKind {
109     VecElement,
110     StrElement,
111     OtherElement,
112 }
113
114 #[deriving(Eq, IterBytes)]
115 pub enum MutabilityCategory {
116     McImmutable, // Immutable.
117     McDeclared,  // Directly declared as mutable.
118     McInherited  // Inherited from the fact that owner is mutable.
119 }
120
121 // `cmt`: "Category, Mutability, and Type".
122 //
123 // a complete categorization of a value indicating where it originated
124 // and how it is located, as well as the mutability of the memory in
125 // which the value is stored.
126 //
127 // *WARNING* The field `cmt.type` is NOT necessarily the same as the
128 // result of `node_id_to_type(cmt.id)`. This is because the `id` is
129 // always the `id` of the node producing the type; in an expression
130 // like `*x`, the type of this deref node is the deref'd type (`T`),
131 // but in a pattern like `@x`, the `@x` pattern is again a
132 // dereference, but its type is the type *before* the dereference
133 // (`@T`). So use `cmt.type` to find the type of the value in a consistent
134 // fashion. For more details, see the method `cat_pattern`
135 #[deriving(Eq)]
136 pub struct cmt_ {
137     id: ast::NodeId,          // id of expr/pat producing this value
138     span: Span,                // span of same expr/pat
139     cat: categorization,       // categorization of expr
140     mutbl: MutabilityCategory, // mutability of expr as lvalue
141     ty: ty::t                  // type of the expr (*see WARNING above*)
142 }
143
144 pub type cmt = @cmt_;
145
146 // We pun on *T to mean both actual deref of a ptr as well
147 // as accessing of components:
148 pub enum deref_kind {
149     deref_ptr(PointerKind),
150     deref_interior(InteriorKind),
151 }
152
153 // Categorizes a derefable type.  Note that we include vectors and strings as
154 // derefable (we model an index as the combination of a deref and then a
155 // pointer adjustment).
156 pub fn opt_deref_kind(t: ty::t) -> Option<deref_kind> {
157     match ty::get(t).sty {
158         ty::ty_uniq(_) |
159         ty::ty_trait(_, _, ty::UniqTraitStore, _, _) |
160         ty::ty_evec(_, ty::vstore_uniq) |
161         ty::ty_estr(ty::vstore_uniq) |
162         ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, ..}) => {
163             Some(deref_ptr(uniq_ptr))
164         }
165
166         ty::ty_rptr(r, mt) |
167         ty::ty_evec(mt, ty::vstore_slice(r)) => {
168             Some(deref_ptr(region_ptr(mt.mutbl, r)))
169         }
170
171         ty::ty_trait(_, _, ty::RegionTraitStore(r), m, _) => {
172             Some(deref_ptr(region_ptr(m, r)))
173         }
174
175         ty::ty_estr(ty::vstore_slice(r)) |
176         ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil,
177                                       region: r, ..}) => {
178             Some(deref_ptr(region_ptr(ast::MutImmutable, r)))
179         }
180
181         ty::ty_box(ref mt) |
182         ty::ty_evec(ref mt, ty::vstore_box) => {
183             Some(deref_ptr(gc_ptr(mt.mutbl)))
184         }
185
186         ty::ty_trait(_, _, ty::BoxTraitStore, m, _) => {
187             Some(deref_ptr(gc_ptr(m)))
188         }
189
190         ty::ty_estr(ty::vstore_box) => {
191             Some(deref_ptr(gc_ptr(ast::MutImmutable)))
192         }
193
194         ty::ty_ptr(ref mt) => {
195             Some(deref_ptr(unsafe_ptr(mt.mutbl)))
196         }
197
198         ty::ty_enum(..) |
199         ty::ty_struct(..) => { // newtype
200             Some(deref_interior(InteriorField(PositionalField(0))))
201         }
202
203         ty::ty_evec(_, ty::vstore_fixed(_)) |
204         ty::ty_estr(ty::vstore_fixed(_)) => {
205             Some(deref_interior(InteriorElement(element_kind(t))))
206         }
207
208         _ => None
209     }
210 }
211
212 pub fn deref_kind(tcx: ty::ctxt, t: ty::t) -> deref_kind {
213     match opt_deref_kind(t) {
214       Some(k) => k,
215       None => {
216         tcx.sess.bug(
217             format!("deref_cat() invoked on non-derefable type {}",
218                  ty_to_str(tcx, t)));
219       }
220     }
221 }
222
223 pub fn cat_expr(tcx: ty::ctxt,
224                 method_map: typeck::method_map,
225                 expr: @ast::Expr)
226              -> cmt {
227     let mcx = &mem_categorization_ctxt {
228         tcx: tcx, method_map: method_map
229     };
230     return mcx.cat_expr(expr);
231 }
232
233 pub fn cat_expr_unadjusted(tcx: ty::ctxt,
234                            method_map: typeck::method_map,
235                            expr: @ast::Expr)
236                         -> cmt {
237     let mcx = &mem_categorization_ctxt {
238         tcx: tcx, method_map: method_map
239     };
240     return mcx.cat_expr_unadjusted(expr);
241 }
242
243 pub fn cat_expr_autoderefd(
244     tcx: ty::ctxt,
245     method_map: typeck::method_map,
246     expr: @ast::Expr,
247     autoderefs: uint) -> cmt
248 {
249     let mcx = &mem_categorization_ctxt {
250         tcx: tcx, method_map: method_map
251     };
252     return mcx.cat_expr_autoderefd(expr, autoderefs);
253 }
254
255 pub fn cat_def(
256     tcx: ty::ctxt,
257     method_map: typeck::method_map,
258     expr_id: ast::NodeId,
259     expr_span: Span,
260     expr_ty: ty::t,
261     def: ast::Def) -> cmt {
262
263     let mcx = &mem_categorization_ctxt {
264         tcx: tcx, method_map: method_map
265     };
266     return mcx.cat_def(expr_id, expr_span, expr_ty, def);
267 }
268
269 pub trait ast_node {
270     fn id(&self) -> ast::NodeId;
271     fn span(&self) -> Span;
272 }
273
274 impl ast_node for @ast::Expr {
275     fn id(&self) -> ast::NodeId { self.id }
276     fn span(&self) -> Span { self.span }
277 }
278
279 impl ast_node for @ast::Pat {
280     fn id(&self) -> ast::NodeId { self.id }
281     fn span(&self) -> Span { self.span }
282 }
283
284 pub struct mem_categorization_ctxt {
285     tcx: ty::ctxt,
286     method_map: typeck::method_map,
287 }
288
289 impl ToStr for MutabilityCategory {
290     fn to_str(&self) -> ~str {
291         format!("{:?}", *self)
292     }
293 }
294
295 impl MutabilityCategory {
296     pub fn from_mutbl(m: ast::Mutability) -> MutabilityCategory {
297         match m {
298             MutImmutable => McImmutable,
299             MutMutable => McDeclared
300         }
301     }
302
303     pub fn inherit(&self) -> MutabilityCategory {
304         match *self {
305             McImmutable => McImmutable,
306             McDeclared => McInherited,
307             McInherited => McInherited
308         }
309     }
310
311     pub fn is_mutable(&self) -> bool {
312         match *self {
313             McImmutable => false,
314             McDeclared | McInherited => true
315         }
316     }
317
318     pub fn is_immutable(&self) -> bool {
319         match *self {
320             McImmutable => true,
321             McDeclared | McInherited => false
322         }
323     }
324
325     pub fn to_user_str(&self) -> &'static str {
326         match *self {
327             McDeclared | McInherited => "mutable",
328             McImmutable => "immutable",
329         }
330     }
331 }
332
333 impl mem_categorization_ctxt {
334     pub fn expr_ty(&self, expr: @ast::Expr) -> ty::t {
335         ty::expr_ty(self.tcx, expr)
336     }
337
338     pub fn pat_ty(&self, pat: @ast::Pat) -> ty::t {
339         ty::node_id_to_type(self.tcx, pat.id)
340     }
341
342     pub fn cat_expr(&self, expr: @ast::Expr) -> cmt {
343         let adjustments = self.tcx.adjustments.borrow();
344         match adjustments.get().find(&expr.id) {
345             None => {
346                 // No adjustments.
347                 self.cat_expr_unadjusted(expr)
348             }
349
350             Some(&@ty::AutoObject(..)) => {
351                 // Implicity casts a concrete object to trait object
352                 // Result is an rvalue
353                 let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
354                 self.cat_rvalue_node(expr, expr_ty)
355             }
356
357             Some(&@ty::AutoAddEnv(..)) => {
358                 // Convert a bare fn to a closure by adding NULL env.
359                 // Result is an rvalue.
360                 let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
361                 self.cat_rvalue_node(expr, expr_ty)
362             }
363
364             Some(
365                 &@ty::AutoDerefRef(
366                     ty::AutoDerefRef {
367                         autoref: Some(_), ..})) => {
368                 // Equivalent to &*expr or something similar.
369                 // Result is an rvalue.
370                 let expr_ty = ty::expr_ty_adjusted(self.tcx, expr);
371                 self.cat_rvalue_node(expr, expr_ty)
372             }
373
374             Some(
375                 &@ty::AutoDerefRef(
376                     ty::AutoDerefRef {
377                         autoref: None, autoderefs: autoderefs})) => {
378                 // Equivalent to *expr or something similar.
379                 self.cat_expr_autoderefd(expr, autoderefs)
380             }
381         }
382     }
383
384     pub fn cat_expr_autoderefd(&self, expr: @ast::Expr, autoderefs: uint)
385                                -> cmt {
386         let mut cmt = self.cat_expr_unadjusted(expr);
387         for deref in range(1u, autoderefs + 1) {
388             cmt = self.cat_deref(expr, cmt, deref);
389         }
390         return cmt;
391     }
392
393     pub fn cat_expr_unadjusted(&self, expr: @ast::Expr) -> cmt {
394         debug!("cat_expr: id={} expr={}",
395                expr.id, pprust::expr_to_str(expr, self.tcx.sess.intr()));
396
397         let expr_ty = self.expr_ty(expr);
398         match expr.node {
399           ast::ExprUnary(_, ast::UnDeref, e_base) => {
400             let method_map = self.method_map.borrow();
401             if method_map.get().contains_key(&expr.id) {
402                 return self.cat_rvalue_node(expr, expr_ty);
403             }
404
405             let base_cmt = self.cat_expr(e_base);
406             self.cat_deref(expr, base_cmt, 0)
407           }
408
409           ast::ExprField(base, f_name, _) => {
410             // Method calls are now a special syntactic form,
411             // so `a.b` should always be a field.
412             let method_map = self.method_map.borrow();
413             assert!(!method_map.get().contains_key(&expr.id));
414
415             let base_cmt = self.cat_expr(base);
416             self.cat_field(expr, base_cmt, f_name, self.expr_ty(expr))
417           }
418
419           ast::ExprIndex(_, base, _) => {
420             let method_map = self.method_map.borrow();
421             if method_map.get().contains_key(&expr.id) {
422                 return self.cat_rvalue_node(expr, expr_ty);
423             }
424
425             let base_cmt = self.cat_expr(base);
426             self.cat_index(expr, base_cmt, 0)
427           }
428
429           ast::ExprPath(_) | ast::ExprSelf => {
430             let def_map = self.tcx.def_map.borrow();
431             let def = def_map.get().get_copy(&expr.id);
432             self.cat_def(expr.id, expr.span, expr_ty, def)
433           }
434
435           ast::ExprParen(e) => self.cat_expr_unadjusted(e),
436
437           ast::ExprAddrOf(..) | ast::ExprCall(..) |
438           ast::ExprAssign(..) | ast::ExprAssignOp(..) |
439           ast::ExprFnBlock(..) | ast::ExprProc(..) | ast::ExprRet(..) |
440           ast::ExprDoBody(..) | ast::ExprUnary(..) |
441           ast::ExprMethodCall(..) | ast::ExprCast(..) | ast::ExprVstore(..) |
442           ast::ExprVec(..) | ast::ExprTup(..) | ast::ExprIf(..) |
443           ast::ExprLogLevel | ast::ExprBinary(..) | ast::ExprWhile(..) |
444           ast::ExprBlock(..) | ast::ExprLoop(..) | ast::ExprMatch(..) |
445           ast::ExprLit(..) | ast::ExprBreak(..) | ast::ExprMac(..) |
446           ast::ExprAgain(..) | ast::ExprStruct(..) | ast::ExprRepeat(..) |
447           ast::ExprInlineAsm(..) => {
448             return self.cat_rvalue_node(expr, expr_ty);
449           }
450
451           ast::ExprForLoop(..) => fail!("non-desugared expr_for_loop")
452         }
453     }
454
455     pub fn cat_def(&self,
456                    id: ast::NodeId,
457                    span: Span,
458                    expr_ty: ty::t,
459                    def: ast::Def)
460                    -> cmt {
461         match def {
462           ast::DefFn(..) | ast::DefStaticMethod(..) | ast::DefMod(_) |
463           ast::DefForeignMod(_) | ast::DefStatic(_, false) |
464           ast::DefUse(_) | ast::DefVariant(..) |
465           ast::DefTrait(_) | ast::DefTy(_) | ast::DefPrimTy(_) |
466           ast::DefTyParam(..) | ast::DefStruct(..) |
467           ast::DefTyParamBinder(..) | ast::DefRegion(_) |
468           ast::DefLabel(_) | ast::DefSelfTy(..) | ast::DefMethod(..) => {
469               @cmt_ {
470                   id:id,
471                   span:span,
472                   cat:cat_static_item,
473                   mutbl: McImmutable,
474                   ty:expr_ty
475               }
476           }
477
478           ast::DefStatic(_, true) => {
479               @cmt_ {
480                   id:id,
481                   span:span,
482                   cat:cat_static_item,
483                   mutbl: McDeclared,
484                   ty:expr_ty
485               }
486           }
487
488           ast::DefArg(vid, binding_mode) => {
489             // Idea: make this could be rewritten to model by-ref
490             // stuff as `&const` and `&mut`?
491
492             // m: mutability of the argument
493             let m = match binding_mode {
494                 ast::BindByValue(ast::MutMutable) => McDeclared,
495                 _ => McImmutable
496             };
497             @cmt_ {
498                 id: id,
499                 span: span,
500                 cat: cat_arg(vid),
501                 mutbl: m,
502                 ty:expr_ty
503             }
504           }
505
506           ast::DefSelf(self_id, mutbl) => {
507             @cmt_ {
508                 id:id,
509                 span:span,
510                 cat:cat_self(self_id),
511                 mutbl: if mutbl { McDeclared } else { McImmutable },
512                 ty:expr_ty
513             }
514           }
515
516           ast::DefUpvar(upvar_id, inner, fn_node_id, _) => {
517               let ty = ty::node_id_to_type(self.tcx, fn_node_id);
518               match ty::get(ty).sty {
519                   ty::ty_closure(ref closure_ty) => {
520                       // Decide whether to use implicit reference or by copy/move
521                       // capture for the upvar. This, combined with the onceness,
522                       // determines whether the closure can move out of it.
523                       let var_is_refd = match (closure_ty.sigil, closure_ty.onceness) {
524                           // Many-shot stack closures can never move out.
525                           (ast::BorrowedSigil, ast::Many) => true,
526                           // 1-shot stack closures can move out.
527                           (ast::BorrowedSigil, ast::Once) => false,
528                           // Heap closures always capture by copy/move, and can
529                           // move out if they are once.
530                           (ast::OwnedSigil, _) |
531                           (ast::ManagedSigil, _) => false,
532
533                       };
534                       if var_is_refd {
535                           let upvar_cmt =
536                               self.cat_def(id, span, expr_ty, *inner);
537                           @cmt_ {
538                               id:id,
539                               span:span,
540                               cat:cat_stack_upvar(upvar_cmt),
541                               mutbl:upvar_cmt.mutbl.inherit(),
542                               ty:upvar_cmt.ty
543                           }
544                       } else {
545                           // FIXME #2152 allow mutation of moved upvars
546                           @cmt_ {
547                               id:id,
548                               span:span,
549                               cat:cat_copied_upvar(CopiedUpvar {
550                                   upvar_id: upvar_id,
551                                   onceness: closure_ty.onceness}),
552                               mutbl:McImmutable,
553                               ty:expr_ty
554                           }
555                       }
556                   }
557                   _ => {
558                       self.tcx.sess.span_bug(
559                           span,
560                           format!("Upvar of non-closure {:?} - {}",
561                                fn_node_id, ty.repr(self.tcx)));
562                   }
563               }
564           }
565
566           ast::DefLocal(vid, binding_mode) |
567           ast::DefBinding(vid, binding_mode) => {
568             // by-value/by-ref bindings are local variables
569             let m = match binding_mode {
570                 ast::BindByValue(ast::MutMutable) => McDeclared,
571                 _ => McImmutable
572             };
573
574             @cmt_ {
575                 id: id,
576                 span: span,
577                 cat: cat_local(vid),
578                 mutbl: m,
579                 ty: expr_ty
580             }
581           }
582         }
583     }
584
585     pub fn cat_rvalue_node<N:ast_node>(&self,
586                                        node: N,
587                                        expr_ty: ty::t) -> cmt {
588         self.cat_rvalue(node.id(),
589                         node.span(),
590                         self.tcx.region_maps.cleanup_scope(node.id()),
591                         expr_ty)
592     }
593
594     pub fn cat_rvalue(&self,
595                       cmt_id: ast::NodeId,
596                       span: Span,
597                       cleanup_scope_id: ast::NodeId,
598                       expr_ty: ty::t) -> cmt {
599         @cmt_ {
600             id:cmt_id,
601             span:span,
602             cat:cat_rvalue(cleanup_scope_id),
603             mutbl:McDeclared,
604             ty:expr_ty
605         }
606     }
607
608     /// inherited mutability: used in cases where the mutability of a
609     /// component is inherited from the base it is a part of. For
610     /// example, a record field is mutable if it is declared mutable
611     /// or if the container is mutable.
612     pub fn inherited_mutability(&self,
613                                 base_m: MutabilityCategory,
614                                 interior_m: ast::Mutability)
615                                 -> MutabilityCategory {
616         match interior_m {
617             MutImmutable => base_m.inherit(),
618             MutMutable => McDeclared
619         }
620     }
621
622     pub fn cat_field<N:ast_node>(&self,
623                                  node: N,
624                                  base_cmt: cmt,
625                                  f_name: ast::Ident,
626                                  f_ty: ty::t)
627                                  -> cmt {
628         @cmt_ {
629             id: node.id(),
630             span: node.span(),
631             cat: cat_interior(base_cmt, InteriorField(NamedField(f_name.name))),
632             mutbl: base_cmt.mutbl.inherit(),
633             ty: f_ty
634         }
635     }
636
637     pub fn cat_deref_fn_or_obj<N:ast_node>(&self,
638                                            node: N,
639                                            base_cmt: cmt,
640                                            deref_cnt: uint)
641                                            -> cmt {
642         // Bit of a hack: the "dereference" of a function pointer like
643         // `@fn()` is a mere logical concept. We interpret it as
644         // dereferencing the environment pointer; of course, we don't
645         // know what type lies at the other end, so we just call it
646         // `()` (the empty tuple).
647
648         let opaque_ty = ty::mk_tup(self.tcx, ~[]);
649         return self.cat_deref_common(node, base_cmt, deref_cnt, opaque_ty);
650     }
651
652     pub fn cat_deref<N:ast_node>(&self,
653                                  node: N,
654                                  base_cmt: cmt,
655                                  deref_cnt: uint)
656                                  -> cmt {
657         let mt = match ty::deref(self.tcx, base_cmt.ty, true) {
658             Some(mt) => mt,
659             None => {
660                 self.tcx.sess.span_bug(
661                     node.span(),
662                     format!("Explicit deref of non-derefable type: {}",
663                          ty_to_str(self.tcx, base_cmt.ty)));
664             }
665         };
666
667         return self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty);
668     }
669
670     pub fn cat_deref_common<N:ast_node>(&self,
671                                         node: N,
672                                         base_cmt: cmt,
673                                         deref_cnt: uint,
674                                         deref_ty: ty::t)
675                                         -> cmt {
676         match deref_kind(self.tcx, base_cmt.ty) {
677             deref_ptr(ptr) => {
678                 // for unique ptrs, we inherit mutability from the
679                 // owning reference.
680                 let m = match ptr {
681                     uniq_ptr => {
682                         base_cmt.mutbl.inherit()
683                     }
684                     gc_ptr(m) | region_ptr(m, _) | unsafe_ptr(m) => {
685                         MutabilityCategory::from_mutbl(m)
686                     }
687                 };
688
689                 @cmt_ {
690                     id:node.id(),
691                     span:node.span(),
692                     cat:cat_deref(base_cmt, deref_cnt, ptr),
693                     mutbl:m,
694                     ty:deref_ty
695                 }
696             }
697
698             deref_interior(interior) => {
699                 let m = base_cmt.mutbl.inherit();
700                 @cmt_ {
701                     id:node.id(),
702                     span:node.span(),
703                     cat:cat_interior(base_cmt, interior),
704                     mutbl:m,
705                     ty:deref_ty
706                 }
707             }
708         }
709     }
710
711     pub fn cat_index<N:ast_node>(&self,
712                                  elt: N,
713                                  base_cmt: cmt,
714                                  derefs: uint)
715                                  -> cmt {
716         //! Creates a cmt for an indexing operation (`[]`); this
717         //! indexing operation may occurs as part of an
718         //! AutoBorrowVec, which when converting a `~[]` to an `&[]`
719         //! effectively takes the address of the 0th element.
720         //!
721         //! One subtle aspect of indexing that may not be
722         //! immediately obvious: for anything other than a fixed-length
723         //! vector, an operation like `x[y]` actually consists of two
724         //! disjoint (from the point of view of borrowck) operations.
725         //! The first is a deref of `x` to create a pointer `p` that points
726         //! at the first element in the array. The second operation is
727         //! an index which adds `y*sizeof(T)` to `p` to obtain the
728         //! pointer to `x[y]`. `cat_index` will produce a resulting
729         //! cmt containing both this deref and the indexing,
730         //! presuming that `base_cmt` is not of fixed-length type.
731         //!
732         //! In the event that a deref is needed, the "deref count"
733         //! is taken from the parameter `derefs`. See the comment
734         //! on the def'n of `root_map_key` in borrowck/mod.rs
735         //! for more details about deref counts; the summary is
736         //! that `derefs` should be 0 for an explicit indexing
737         //! operation and N+1 for an indexing that is part of
738         //! an auto-adjustment, where N is the number of autoderefs
739         //! in that adjustment.
740         //!
741         //! # Parameters
742         //! - `elt`: the AST node being indexed
743         //! - `base_cmt`: the cmt of `elt`
744         //! - `derefs`: the deref number to be used for
745         //!   the implicit index deref, if any (see above)
746
747         let element_ty = match ty::index(base_cmt.ty) {
748           Some(ref mt) => mt.ty,
749           None => {
750             self.tcx.sess.span_bug(
751                 elt.span(),
752                 format!("Explicit index of non-index type `{}`",
753                      ty_to_str(self.tcx, base_cmt.ty)));
754           }
755         };
756
757         return match deref_kind(self.tcx, base_cmt.ty) {
758           deref_ptr(ptr) => {
759             // for unique ptrs, we inherit mutability from the
760             // owning reference.
761             let m = match ptr {
762               uniq_ptr => {
763                 base_cmt.mutbl.inherit()
764               }
765               gc_ptr(m) | region_ptr(m, _) | unsafe_ptr(m) => {
766                 MutabilityCategory::from_mutbl(m)
767               }
768             };
769
770             // the deref is explicit in the resulting cmt
771             let deref_cmt = @cmt_ {
772                 id:elt.id(),
773                 span:elt.span(),
774                 cat:cat_deref(base_cmt, derefs, ptr),
775                 mutbl:m,
776                 ty:element_ty
777             };
778
779             interior(elt, deref_cmt, base_cmt.ty, m, element_ty)
780           }
781
782           deref_interior(_) => {
783             // fixed-length vectors have no deref
784             let m = base_cmt.mutbl.inherit();
785             interior(elt, base_cmt, base_cmt.ty, m, element_ty)
786           }
787         };
788
789         fn interior<N: ast_node>(elt: N,
790                                  of_cmt: cmt,
791                                  vec_ty: ty::t,
792                                  mutbl: MutabilityCategory,
793                                  element_ty: ty::t) -> cmt
794         {
795             @cmt_ {
796                 id:elt.id(),
797                 span:elt.span(),
798                 cat:cat_interior(of_cmt, InteriorElement(element_kind(vec_ty))),
799                 mutbl:mutbl,
800                 ty:element_ty
801             }
802         }
803     }
804
805     pub fn cat_imm_interior<N:ast_node>(&self,
806                                         node: N,
807                                         base_cmt: cmt,
808                                         interior_ty: ty::t,
809                                         interior: InteriorKind)
810                                         -> cmt {
811         @cmt_ {
812             id: node.id(),
813             span: node.span(),
814             cat: cat_interior(base_cmt, interior),
815             mutbl: base_cmt.mutbl.inherit(),
816             ty: interior_ty
817         }
818     }
819
820     pub fn cat_downcast<N:ast_node>(&self,
821                                     node: N,
822                                     base_cmt: cmt,
823                                     downcast_ty: ty::t)
824                                     -> cmt {
825         @cmt_ {
826             id: node.id(),
827             span: node.span(),
828             cat: cat_downcast(base_cmt),
829             mutbl: base_cmt.mutbl.inherit(),
830             ty: downcast_ty
831         }
832     }
833
834     pub fn cat_pattern(&self,
835                        cmt: cmt,
836                        pat: @ast::Pat,
837                        op: |cmt, @ast::Pat|) {
838         // Here, `cmt` is the categorization for the value being
839         // matched and pat is the pattern it is being matched against.
840         //
841         // In general, the way that this works is that we walk down
842         // the pattern, constructing a cmt that represents the path
843         // that will be taken to reach the value being matched.
844         //
845         // When we encounter named bindings, we take the cmt that has
846         // been built up and pass it off to guarantee_valid() so that
847         // we can be sure that the binding will remain valid for the
848         // duration of the arm.
849         //
850         // (..) There is subtlety concerning the correspondence between
851         // pattern ids and types as compared to *expression* ids and
852         // types. This is explained briefly. on the definition of the
853         // type `cmt`, so go off and read what it says there, then
854         // come back and I'll dive into a bit more detail here. :) OK,
855         // back?
856         //
857         // In general, the id of the cmt should be the node that
858         // "produces" the value---patterns aren't executable code
859         // exactly, but I consider them to "execute" when they match a
860         // value. So if you have something like:
861         //
862         //     let x = @@3;
863         //     match x {
864         //       @@y { ... }
865         //     }
866         //
867         // In this case, the cmt and the relevant ids would be:
868         //
869         //     CMT             Id                  Type of Id Type of cmt
870         //
871         //     local(x)->@->@
872         //     ^~~~~~~^        `x` from discr      @@int      @@int
873         //     ^~~~~~~~~~^     `@@y` pattern node  @@int      @int
874         //     ^~~~~~~~~~~~~^  `@y` pattern node   @int       int
875         //
876         // You can see that the types of the id and the cmt are in
877         // sync in the first line, because that id is actually the id
878         // of an expression. But once we get to pattern ids, the types
879         // step out of sync again. So you'll see below that we always
880         // get the type of the *subpattern* and use that.
881
882         let tcx = self.tcx;
883         debug!("cat_pattern: id={} pat={} cmt={}",
884                pat.id, pprust::pat_to_str(pat, tcx.sess.intr()),
885                cmt.repr(tcx));
886         let _i = indenter();
887
888         op(cmt, pat);
889
890         match pat.node {
891           ast::PatWild | ast::PatWildMulti => {
892             // _
893           }
894
895           ast::PatEnum(_, None) => {
896             // variant(..)
897           }
898           ast::PatEnum(_, Some(ref subpats)) => {
899             let def_map = self.tcx.def_map.borrow();
900             match def_map.get().find(&pat.id) {
901                 Some(&ast::DefVariant(enum_did, _, _)) => {
902                     // variant(x, y, z)
903
904                     let downcast_cmt = {
905                         if ty::enum_is_univariant(tcx, enum_did) {
906                             cmt // univariant, no downcast needed
907                         } else {
908                             self.cat_downcast(pat, cmt, cmt.ty)
909                         }
910                     };
911
912                     for (i, &subpat) in subpats.iter().enumerate() {
913                         let subpat_ty = self.pat_ty(subpat); // see (..)
914
915                         let subcmt =
916                             self.cat_imm_interior(
917                                 pat, downcast_cmt, subpat_ty,
918                                 InteriorField(PositionalField(i)));
919
920                         self.cat_pattern(subcmt, subpat, |x,y| op(x,y));
921                     }
922                 }
923                 Some(&ast::DefFn(..)) |
924                 Some(&ast::DefStruct(..)) => {
925                     for (i, &subpat) in subpats.iter().enumerate() {
926                         let subpat_ty = self.pat_ty(subpat); // see (..)
927                         let cmt_field =
928                             self.cat_imm_interior(
929                                 pat, cmt, subpat_ty,
930                                 InteriorField(PositionalField(i)));
931                         self.cat_pattern(cmt_field, subpat, |x,y| op(x,y));
932                     }
933                 }
934                 Some(&ast::DefStatic(..)) => {
935                     for &subpat in subpats.iter() {
936                         self.cat_pattern(cmt, subpat, |x,y| op(x,y));
937                     }
938                 }
939                 _ => {
940                     self.tcx.sess.span_bug(
941                         pat.span,
942                         "enum pattern didn't resolve to enum or struct");
943                 }
944             }
945           }
946
947           ast::PatIdent(_, _, Some(subpat)) => {
948               self.cat_pattern(cmt, subpat, op);
949           }
950
951           ast::PatIdent(_, _, None) => {
952               // nullary variant or identifier: ignore
953           }
954
955           ast::PatStruct(_, ref field_pats, _) => {
956             // {f1: p1, ..., fN: pN}
957             for fp in field_pats.iter() {
958                 let field_ty = self.pat_ty(fp.pat); // see (..)
959                 let cmt_field = self.cat_field(pat, cmt, fp.ident, field_ty);
960                 self.cat_pattern(cmt_field, fp.pat, |x,y| op(x,y));
961             }
962           }
963
964           ast::PatTup(ref subpats) => {
965             // (p1, ..., pN)
966             for (i, &subpat) in subpats.iter().enumerate() {
967                 let subpat_ty = self.pat_ty(subpat); // see (..)
968                 let subcmt =
969                     self.cat_imm_interior(
970                         pat, cmt, subpat_ty,
971                         InteriorField(PositionalField(i)));
972                 self.cat_pattern(subcmt, subpat, |x,y| op(x,y));
973             }
974           }
975
976           ast::PatBox(subpat) | ast::PatUniq(subpat) |
977           ast::PatRegion(subpat) => {
978             // @p1, ~p1
979             let subcmt = self.cat_deref(pat, cmt, 0);
980             self.cat_pattern(subcmt, subpat, op);
981           }
982
983           ast::PatVec(ref before, slice, ref after) => {
984               let elt_cmt = self.cat_index(pat, cmt, 0);
985               for &before_pat in before.iter() {
986                   self.cat_pattern(elt_cmt, before_pat, |x,y| op(x,y));
987               }
988               for &slice_pat in slice.iter() {
989                   let slice_ty = self.pat_ty(slice_pat);
990                   let slice_cmt = self.cat_rvalue_node(pat, slice_ty);
991                   self.cat_pattern(slice_cmt, slice_pat, |x,y| op(x,y));
992               }
993               for &after_pat in after.iter() {
994                   self.cat_pattern(elt_cmt, after_pat, |x,y| op(x,y));
995               }
996           }
997
998           ast::PatLit(_) | ast::PatRange(_, _) => {
999               /*always ok*/
1000           }
1001         }
1002     }
1003
1004     pub fn mut_to_str(&self, mutbl: ast::Mutability) -> ~str {
1005         match mutbl {
1006           MutMutable => ~"mutable",
1007           MutImmutable => ~"immutable"
1008         }
1009     }
1010
1011     pub fn cmt_to_str(&self, cmt: cmt) -> ~str {
1012         match cmt.cat {
1013           cat_static_item => {
1014               ~"static item"
1015           }
1016           cat_copied_upvar(_) => {
1017               ~"captured outer variable in a heap closure"
1018           }
1019           cat_rvalue(..) => {
1020               ~"non-lvalue"
1021           }
1022           cat_local(_) => {
1023               ~"local variable"
1024           }
1025           cat_self(_) => {
1026               ~"self value"
1027           }
1028           cat_arg(..) => {
1029               ~"argument"
1030           }
1031           cat_deref(_, _, pk) => {
1032               format!("dereference of {} pointer", ptr_sigil(pk))
1033           }
1034           cat_interior(_, InteriorField(NamedField(_))) => {
1035               ~"field"
1036           }
1037           cat_interior(_, InteriorField(PositionalField(_))) => {
1038               ~"anonymous field"
1039           }
1040           cat_interior(_, InteriorElement(VecElement)) => {
1041               ~"vec content"
1042           }
1043           cat_interior(_, InteriorElement(StrElement)) => {
1044               ~"str content"
1045           }
1046           cat_interior(_, InteriorElement(OtherElement)) => {
1047               ~"indexed content"
1048           }
1049           cat_stack_upvar(_) => {
1050               ~"captured outer variable"
1051           }
1052           cat_discr(cmt, _) => {
1053             self.cmt_to_str(cmt)
1054           }
1055           cat_downcast(cmt) => {
1056             self.cmt_to_str(cmt)
1057           }
1058         }
1059     }
1060
1061     pub fn region_to_str(&self, r: ty::Region) -> ~str {
1062         region_ptr_to_str(self.tcx, r)
1063     }
1064 }
1065
1066 /// The node_id here is the node of the expression that references the field.
1067 /// This function looks it up in the def map in case the type happens to be
1068 /// an enum to determine which variant is in use.
1069 pub fn field_mutbl(tcx: ty::ctxt,
1070                    base_ty: ty::t,
1071                    // FIXME #6993: change type to Name
1072                    f_name: ast::Ident,
1073                    node_id: ast::NodeId)
1074                 -> Option<ast::Mutability> {
1075     // Need to refactor so that struct/enum fields can be treated uniformly.
1076     match ty::get(base_ty).sty {
1077       ty::ty_struct(did, _) => {
1078         let r = ty::lookup_struct_fields(tcx, did);
1079         for fld in r.iter() {
1080             if fld.name == f_name.name {
1081                 return Some(ast::MutImmutable);
1082             }
1083         }
1084       }
1085       ty::ty_enum(..) => {
1086         let def_map = tcx.def_map.borrow();
1087         match def_map.get().get_copy(&node_id) {
1088           ast::DefVariant(_, variant_id, _) => {
1089             let r = ty::lookup_struct_fields(tcx, variant_id);
1090             for fld in r.iter() {
1091                 if fld.name == f_name.name {
1092                     return Some(ast::MutImmutable);
1093                 }
1094             }
1095           }
1096           _ => {}
1097         }
1098       }
1099       _ => { }
1100     }
1101
1102     return None;
1103 }
1104
1105 pub enum AliasableReason {
1106     AliasableManaged(ast::Mutability),
1107     AliasableBorrowed(ast::Mutability),
1108     AliasableOther
1109 }
1110
1111 impl cmt_ {
1112     pub fn guarantor(@self) -> cmt {
1113         //! Returns `self` after stripping away any owned pointer derefs or
1114         //! interior content. The return value is basically the `cmt` which
1115         //! determines how long the value in `self` remains live.
1116
1117         match self.cat {
1118             cat_rvalue(..) |
1119             cat_static_item |
1120             cat_copied_upvar(..) |
1121             cat_local(..) |
1122             cat_self(..) |
1123             cat_arg(..) |
1124             cat_deref(_, _, unsafe_ptr(..)) |
1125             cat_deref(_, _, gc_ptr(..)) |
1126             cat_deref(_, _, region_ptr(..)) => {
1127                 self
1128             }
1129             cat_downcast(b) |
1130             cat_stack_upvar(b) |
1131             cat_discr(b, _) |
1132             cat_interior(b, _) |
1133             cat_deref(b, _, uniq_ptr) => {
1134                 b.guarantor()
1135             }
1136         }
1137     }
1138
1139     pub fn is_freely_aliasable(&self) -> bool {
1140         self.freely_aliasable().is_some()
1141     }
1142
1143     pub fn freely_aliasable(&self) -> Option<AliasableReason> {
1144         /*!
1145          * Returns `Some(_)` if this lvalue represents a freely aliasable
1146          * pointer type.
1147          */
1148
1149         // Maybe non-obvious: copied upvars can only be considered
1150         // non-aliasable in once closures, since any other kind can be
1151         // aliased and eventually recused.
1152
1153         match self.cat {
1154             cat_copied_upvar(CopiedUpvar {onceness: ast::Once, ..}) |
1155             cat_rvalue(..) |
1156             cat_local(..) |
1157             cat_arg(_) |
1158             cat_self(..) |
1159             cat_deref(_, _, unsafe_ptr(..)) | // of course it is aliasable, but...
1160             cat_deref(_, _, region_ptr(MutMutable, _)) => {
1161                 None
1162             }
1163
1164             cat_copied_upvar(CopiedUpvar {onceness: ast::Many, ..}) |
1165             cat_static_item(..) => {
1166                 Some(AliasableOther)
1167             }
1168
1169             cat_deref(_, _, gc_ptr(m)) => {
1170                 Some(AliasableManaged(m))
1171             }
1172
1173             cat_deref(_, _, region_ptr(m @ MutImmutable, _)) => {
1174                 Some(AliasableBorrowed(m))
1175             }
1176
1177             cat_downcast(..) |
1178             cat_stack_upvar(..) |
1179             cat_deref(_, _, uniq_ptr) |
1180             cat_interior(..) |
1181             cat_discr(..) => {
1182                 None
1183             }
1184         }
1185     }
1186 }
1187
1188 impl Repr for cmt_ {
1189     fn repr(&self, tcx: ty::ctxt) -> ~str {
1190         format!("\\{{} id:{} m:{:?} ty:{}\\}",
1191              self.cat.repr(tcx),
1192              self.id,
1193              self.mutbl,
1194              self.ty.repr(tcx))
1195     }
1196 }
1197
1198 impl Repr for categorization {
1199     fn repr(&self, tcx: ty::ctxt) -> ~str {
1200         match *self {
1201             cat_static_item |
1202             cat_rvalue(..) |
1203             cat_copied_upvar(..) |
1204             cat_local(..) |
1205             cat_self(..) |
1206             cat_arg(..) => {
1207                 format!("{:?}", *self)
1208             }
1209             cat_deref(cmt, derefs, ptr) => {
1210                 format!("{}->({}, {})", cmt.cat.repr(tcx),
1211                      ptr_sigil(ptr), derefs)
1212             }
1213             cat_interior(cmt, interior) => {
1214                 format!("{}.{}",
1215                      cmt.cat.repr(tcx),
1216                      interior.repr(tcx))
1217             }
1218             cat_downcast(cmt) => {
1219                 format!("{}->(enum)", cmt.cat.repr(tcx))
1220             }
1221             cat_stack_upvar(cmt) |
1222             cat_discr(cmt, _) => {
1223                 cmt.cat.repr(tcx)
1224             }
1225         }
1226     }
1227 }
1228
1229 pub fn ptr_sigil(ptr: PointerKind) -> ~str {
1230     match ptr {
1231         uniq_ptr => ~"~",
1232         gc_ptr(_) => ~"@",
1233         region_ptr(_, _) => ~"&",
1234         unsafe_ptr(_) => ~"*"
1235     }
1236 }
1237
1238 impl Repr for InteriorKind {
1239     fn repr(&self, _tcx: ty::ctxt) -> ~str {
1240         match *self {
1241             InteriorField(NamedField(fld)) => token::interner_get(fld).to_owned(),
1242             InteriorField(PositionalField(i)) => format!("\\#{:?}", i),
1243             InteriorElement(_) => ~"[]",
1244         }
1245     }
1246 }
1247
1248 fn element_kind(t: ty::t) -> ElementKind {
1249     match ty::get(t).sty {
1250         ty::ty_evec(..) => VecElement,
1251         ty::ty_estr(..) => StrElement,
1252         _ => OtherElement
1253     }
1254 }