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