1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
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.
13 //! The job of the categorization module is to analyze an expression to
14 //! determine what kind of memory is used in evaluating it (for example,
15 //! where dereferences occur and what kind of pointer is dereferenced;
16 //! whether the memory is mutable; etc)
18 //! Categorization effectively transforms all of our expressions into
19 //! expressions of the following forms (the actual enum has many more
20 //! possibilities, naturally, but they are all variants of these base
23 //! E = rvalue // some computed rvalue
24 //! | x // address of a local variable or argument
25 //! | *E // deref of a ptr
26 //! | E.comp // access to an interior component
28 //! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
29 //! address where the result is to be found. If Expr is an lvalue, then this
30 //! is the address of the lvalue. If Expr is an rvalue, this is the address of
31 //! some temporary spot in memory where the result is stored.
33 //! Now, cat_expr() classifies the expression Expr and the address A=ToAddr(Expr)
36 //! - cat: what kind of expression was this? This is a subset of the
37 //! full expression forms which only includes those that we care about
38 //! for the purpose of the analysis.
39 //! - mutbl: mutability of the address A
40 //! - ty: the type of data found at the address A
42 //! The resulting categorization tree differs somewhat from the expressions
43 //! themselves. For example, auto-derefs are explicit. Also, an index a[b] is
44 //! decomposed into two operations: a dereference to reach the array data and
45 //! then an index to jump forward to the relevant item.
47 //! ## By-reference upvars
49 //! One part of the translation which may be non-obvious is that we translate
50 //! closure upvars into the dereference of a borrowed pointer; this more closely
51 //! resembles the runtime translation. So, for example, if we had:
55 //! let inc = || x += y;
57 //! Then when we categorize `x` (*within* the closure) we would yield a
58 //! result of `*x'`, effectively, where `x'` is a `cat_upvar` reference
59 //! tied to `x`. The type of `x'` will be a borrowed pointer.
61 #![allow(non_camel_case_types)]
63 pub use self::PointerKind
::*;
64 pub use self::InteriorKind
::*;
65 pub use self::FieldName
::*;
66 pub use self::ElementKind
::*;
67 pub use self::MutabilityCategory
::*;
68 pub use self::AliasableReason
::*;
69 pub use self::Note
::*;
70 pub use self::deref_kind
::*;
71 pub use self::categorization
::*;
73 use self::Aliasability
::*;
76 use middle
::check_const
;
79 use middle
::ty
::{self, Ty}
;
80 use util
::nodemap
::NodeMap
;
82 use syntax
::ast
::{MutImmutable, MutMutable}
;
84 use syntax
::codemap
::Span
;
86 use std
::cell
::RefCell
;
90 #[derive(Clone, PartialEq)]
91 pub enum categorization
<'tcx
> {
92 cat_rvalue(ty
::Region
), // temporary val, argument is its scope
94 cat_upvar(Upvar
), // upvar referenced by closure env
95 cat_local(ast
::NodeId
), // local variable
96 cat_deref(cmt
<'tcx
>, usize, PointerKind
), // deref of a ptr
97 cat_interior(cmt
<'tcx
>, InteriorKind
), // something interior: field, tuple, etc
98 cat_downcast(cmt
<'tcx
>, ast
::DefId
), // selects a particular enum variant (*1)
100 // (*1) downcast is only required if the enum has more than one variant
103 // Represents any kind of upvar
104 #[derive(Clone, Copy, PartialEq)]
107 pub kind
: ty
::ClosureKind
110 // different kinds of pointers:
111 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
112 pub enum PointerKind
{
117 BorrowedPtr(ty
::BorrowKind
, ty
::Region
),
120 UnsafePtr(ast
::Mutability
),
122 /// Implicit deref of the `&T` that results from an overloaded index `[]`.
123 Implicit(ty
::BorrowKind
, ty
::Region
),
126 // We use the term "interior" to mean "something reachable from the
127 // base without a pointer dereference", e.g. a field
128 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
129 pub enum InteriorKind
{
130 InteriorField(FieldName
),
131 InteriorElement(InteriorOffsetKind
, ElementKind
),
134 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
136 NamedField(ast
::Name
),
137 PositionalField(usize)
140 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
141 pub enum InteriorOffsetKind
{
142 Index
, // e.g. `array_expr[index_expr]`
143 Pattern
, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
146 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
147 pub enum ElementKind
{
152 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
153 pub enum MutabilityCategory
{
154 McImmutable
, // Immutable.
155 McDeclared
, // Directly declared as mutable.
156 McInherited
, // Inherited from the fact that owner is mutable.
159 // A note about the provenance of a `cmt`. This is used for
160 // special-case handling of upvars such as mutability inference.
161 // Upvar categorization can generate a variable number of nested
162 // derefs. The note allows detecting them without deep pattern
163 // matching on the categorization.
164 #[derive(Clone, Copy, PartialEq, Debug)]
166 NoteClosureEnv(ty
::UpvarId
), // Deref through closure env
167 NoteUpvarRef(ty
::UpvarId
), // Deref through by-ref upvar
168 NoteNone
// Nothing special
171 // `cmt`: "Category, Mutability, and Type".
173 // a complete categorization of a value indicating where it originated
174 // and how it is located, as well as the mutability of the memory in
175 // which the value is stored.
177 // *WARNING* The field `cmt.type` is NOT necessarily the same as the
178 // result of `node_id_to_type(cmt.id)`. This is because the `id` is
179 // always the `id` of the node producing the type; in an expression
180 // like `*x`, the type of this deref node is the deref'd type (`T`),
181 // but in a pattern like `@x`, the `@x` pattern is again a
182 // dereference, but its type is the type *before* the dereference
183 // (`@T`). So use `cmt.ty` to find the type of the value in a consistent
184 // fashion. For more details, see the method `cat_pattern`
185 #[derive(Clone, PartialEq)]
186 pub struct cmt_
<'tcx
> {
187 pub id
: ast
::NodeId
, // id of expr/pat producing this value
188 pub span
: Span
, // span of same expr/pat
189 pub cat
: categorization
<'tcx
>, // categorization of expr
190 pub mutbl
: MutabilityCategory
, // mutability of expr as lvalue
191 pub ty
: Ty
<'tcx
>, // type of the expr (*see WARNING above*)
192 pub note
: Note
, // Note about the provenance of this cmt
195 pub type cmt
<'tcx
> = Rc
<cmt_
<'tcx
>>;
197 // We pun on *T to mean both actual deref of a ptr as well
198 // as accessing of components:
199 #[derive(Copy, Clone)]
200 pub enum deref_kind
{
201 deref_ptr(PointerKind
),
202 deref_interior(InteriorKind
),
205 type DerefKindContext
= Option
<InteriorOffsetKind
>;
207 // Categorizes a derefable type. Note that we include vectors and strings as
208 // derefable (we model an index as the combination of a deref and then a
209 // pointer adjustment).
210 fn deref_kind(t
: Ty
, context
: DerefKindContext
) -> McResult
<deref_kind
> {
213 Ok(deref_ptr(Unique
))
216 ty
::TyRef(r
, mt
) => {
217 let kind
= ty
::BorrowKind
::from_mutbl(mt
.mutbl
);
218 Ok(deref_ptr(BorrowedPtr(kind
, *r
)))
221 ty
::TyRawPtr(ref mt
) => {
222 Ok(deref_ptr(UnsafePtr(mt
.mutbl
)))
226 ty
::TyStruct(..) => { // newtype
227 Ok(deref_interior(InteriorField(PositionalField(0))))
230 ty
::TyArray(_
, _
) | ty
::TySlice(_
) | ty
::TyStr
=> {
231 // no deref of indexed content without supplying InteriorOffsetKind
232 if let Some(context
) = context
{
233 Ok(deref_interior(InteriorElement(context
, element_kind(t
))))
244 fn id(&self) -> ast
::NodeId
;
245 fn span(&self) -> Span
;
248 impl ast_node
for ast
::Expr
{
249 fn id(&self) -> ast
::NodeId { self.id }
250 fn span(&self) -> Span { self.span }
253 impl ast_node
for ast
::Pat
{
254 fn id(&self) -> ast
::NodeId { self.id }
255 fn span(&self) -> Span { self.span }
258 pub struct MemCategorizationContext
<'t
,TYPER
:'t
> {
262 impl<'t
,TYPER
:'t
> Copy
for MemCategorizationContext
<'t
,TYPER
> {}
263 impl<'t
,TYPER
:'t
> Clone
for MemCategorizationContext
<'t
,TYPER
> {
264 fn clone(&self) -> MemCategorizationContext
<'t
,TYPER
> { *self }
267 pub type McResult
<T
> = Result
<T
, ()>;
269 /// The `Typer` trait provides the interface for the mem-categorization
270 /// module to the results of the type check. It can be used to query
271 /// the type assigned to an expression node, to inquire after adjustments,
274 /// This interface is needed because mem-categorization is used from
275 /// two places: `regionck` and `borrowck`. `regionck` executes before
276 /// type inference is complete, and hence derives types and so on from
277 /// intermediate tables. This also implies that type errors can occur,
278 /// and hence `node_ty()` and friends return a `Result` type -- any
279 /// error will propagate back up through the mem-categorization
282 /// In the borrow checker, in contrast, type checking is complete and we
283 /// know that no errors have occurred, so we simply consult the tcx and we
284 /// can be sure that only `Ok` results will occur.
285 pub trait Typer
<'tcx
> : ty
::ClosureTyper
<'tcx
> {
286 fn node_ty(&self, id
: ast
::NodeId
) -> McResult
<Ty
<'tcx
>>;
287 fn expr_ty_adjusted(&self, expr
: &ast
::Expr
) -> McResult
<Ty
<'tcx
>>;
288 fn type_moves_by_default(&self, span
: Span
, ty
: Ty
<'tcx
>) -> bool
;
289 fn node_method_ty(&self, method_call
: ty
::MethodCall
) -> Option
<Ty
<'tcx
>>;
290 fn node_method_origin(&self, method_call
: ty
::MethodCall
)
291 -> Option
<ty
::MethodOrigin
<'tcx
>>;
292 fn adjustments
<'a
>(&'a
self) -> &'a RefCell
<NodeMap
<ty
::AutoAdjustment
<'tcx
>>>;
293 fn is_method_call(&self, id
: ast
::NodeId
) -> bool
;
294 fn temporary_scope(&self, rvalue_id
: ast
::NodeId
) -> Option
<region
::CodeExtent
>;
295 fn upvar_capture(&self, upvar_id
: ty
::UpvarId
) -> Option
<ty
::UpvarCapture
>;
298 impl MutabilityCategory
{
299 pub fn from_mutbl(m
: ast
::Mutability
) -> MutabilityCategory
{
301 MutImmutable
=> McImmutable
,
302 MutMutable
=> McDeclared
304 debug
!("MutabilityCategory::{}({:?}) => {:?}",
305 "from_mutbl", m
, ret
);
309 pub fn from_borrow_kind(borrow_kind
: ty
::BorrowKind
) -> MutabilityCategory
{
310 let ret
= match borrow_kind
{
311 ty
::ImmBorrow
=> McImmutable
,
312 ty
::UniqueImmBorrow
=> McImmutable
,
313 ty
::MutBorrow
=> McDeclared
,
315 debug
!("MutabilityCategory::{}({:?}) => {:?}",
316 "from_borrow_kind", borrow_kind
, ret
);
320 fn from_pointer_kind(base_mutbl
: MutabilityCategory
,
321 ptr
: PointerKind
) -> MutabilityCategory
{
322 let ret
= match ptr
{
326 BorrowedPtr(borrow_kind
, _
) | Implicit(borrow_kind
, _
) => {
327 MutabilityCategory
::from_borrow_kind(borrow_kind
)
330 MutabilityCategory
::from_mutbl(m
)
333 debug
!("MutabilityCategory::{}({:?}, {:?}) => {:?}",
334 "from_pointer_kind", base_mutbl
, ptr
, ret
);
338 fn from_local(tcx
: &ty
::ctxt
, id
: ast
::NodeId
) -> MutabilityCategory
{
339 let ret
= match tcx
.map
.get(id
) {
340 ast_map
::NodeLocal(p
) | ast_map
::NodeArg(p
) => match p
.node
{
341 ast
::PatIdent(bind_mode
, _
, _
) => {
342 if bind_mode
== ast
::BindByValue(ast
::MutMutable
) {
348 _
=> tcx
.sess
.span_bug(p
.span
, "expected identifier pattern")
350 _
=> tcx
.sess
.span_bug(tcx
.map
.span(id
), "expected identifier pattern")
352 debug
!("MutabilityCategory::{}(tcx, id={:?}) => {:?}",
353 "from_local", id
, ret
);
357 pub fn inherit(&self) -> MutabilityCategory
{
358 let ret
= match *self {
359 McImmutable
=> McImmutable
,
360 McDeclared
=> McInherited
,
361 McInherited
=> McInherited
,
363 debug
!("{:?}.inherit() => {:?}", self, ret
);
367 pub fn is_mutable(&self) -> bool
{
368 let ret
= match *self {
369 McImmutable
=> false,
373 debug
!("{:?}.is_mutable() => {:?}", self, ret
);
377 pub fn is_immutable(&self) -> bool
{
378 let ret
= match *self {
380 McDeclared
| McInherited
=> false
382 debug
!("{:?}.is_immutable() => {:?}", self, ret
);
386 pub fn to_user_str(&self) -> &'
static str {
388 McDeclared
| McInherited
=> "mutable",
389 McImmutable
=> "immutable",
394 impl<'t
,'tcx
,TYPER
:Typer
<'tcx
>> MemCategorizationContext
<'t
,TYPER
> {
395 pub fn new(typer
: &'t TYPER
) -> MemCategorizationContext
<'t
,TYPER
> {
396 MemCategorizationContext { typer: typer }
399 fn tcx(&self) -> &'t ty
::ctxt
<'tcx
> {
403 fn expr_ty(&self, expr
: &ast
::Expr
) -> McResult
<Ty
<'tcx
>> {
404 self.typer
.node_ty(expr
.id
)
407 fn expr_ty_adjusted(&self, expr
: &ast
::Expr
) -> McResult
<Ty
<'tcx
>> {
408 let unadjusted_ty
= try
!(self.expr_ty(expr
));
409 Ok(ty
::adjust_ty(self.tcx(), expr
.span
, expr
.id
, unadjusted_ty
,
410 self.typer
.adjustments().borrow().get(&expr
.id
),
411 |method_call
| self.typer
.node_method_ty(method_call
)))
414 fn node_ty(&self, id
: ast
::NodeId
) -> McResult
<Ty
<'tcx
>> {
415 self.typer
.node_ty(id
)
418 fn pat_ty(&self, pat
: &ast
::Pat
) -> McResult
<Ty
<'tcx
>> {
419 let base_ty
= try
!(self.typer
.node_ty(pat
.id
));
420 // FIXME (Issue #18207): This code detects whether we are
421 // looking at a `ref x`, and if so, figures out what the type
422 // *being borrowed* is. But ideally we would put in a more
423 // fundamental fix to this conflated use of the node id.
424 let ret_ty
= match pat
.node
{
425 ast
::PatIdent(ast
::BindByRef(_
), _
, _
) => {
426 // a bind-by-ref means that the base_ty will be the type of the ident itself,
427 // but what we want here is the type of the underlying value being borrowed.
428 // So peel off one-level, turning the &T into T.
429 match ty
::deref(base_ty
, false) {
431 None
=> { return Err(()); }
436 debug
!("pat_ty(pat={:?}) base_ty={:?} ret_ty={:?}",
437 pat
, base_ty
, ret_ty
);
441 pub fn cat_expr(&self, expr
: &ast
::Expr
) -> McResult
<cmt
<'tcx
>> {
442 match self.typer
.adjustments().borrow().get(&expr
.id
) {
445 self.cat_expr_unadjusted(expr
)
448 Some(adjustment
) => {
452 autoref
: None
, unsize
: None
, autoderefs
, ..}) => {
453 // Equivalent to *expr or something similar.
454 self.cat_expr_autoderefd(expr
, autoderefs
)
457 ty
::AdjustReifyFnPointer
|
458 ty
::AdjustUnsafeFnPointer
|
459 ty
::AdjustDerefRef(_
) => {
460 debug
!("cat_expr({:?}): {:?}",
463 // Result is an rvalue.
464 let expr_ty
= try
!(self.expr_ty_adjusted(expr
));
465 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
472 pub fn cat_expr_autoderefd(&self,
475 -> McResult
<cmt
<'tcx
>> {
476 let mut cmt
= try
!(self.cat_expr_unadjusted(expr
));
477 debug
!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
480 for deref
in 1..autoderefs
+ 1 {
481 cmt
= try
!(self.cat_deref(expr
, cmt
, deref
, None
));
486 pub fn cat_expr_unadjusted(&self, expr
: &ast
::Expr
) -> McResult
<cmt
<'tcx
>> {
487 debug
!("cat_expr: id={} expr={:?}", expr
.id
, expr
);
489 let expr_ty
= try
!(self.expr_ty(expr
));
491 ast
::ExprUnary(ast
::UnDeref
, ref e_base
) => {
492 let base_cmt
= try
!(self.cat_expr(&**e_base
));
493 self.cat_deref(expr
, base_cmt
, 0, None
)
496 ast
::ExprField(ref base
, f_name
) => {
497 let base_cmt
= try
!(self.cat_expr(&**base
));
498 debug
!("cat_expr(cat_field): id={} expr={:?} base={:?}",
502 Ok(self.cat_field(expr
, base_cmt
, f_name
.node
.name
, expr_ty
))
505 ast
::ExprTupField(ref base
, idx
) => {
506 let base_cmt
= try
!(self.cat_expr(&**base
));
507 Ok(self.cat_tup_field(expr
, base_cmt
, idx
.node
, expr_ty
))
510 ast
::ExprIndex(ref base
, _
) => {
511 let method_call
= ty
::MethodCall
::expr(expr
.id());
512 let context
= InteriorOffsetKind
::Index
;
513 match self.typer
.node_method_ty(method_call
) {
515 // If this is an index implemented by a method call, then it
516 // will include an implicit deref of the result.
517 let ret_ty
= self.overloaded_method_return_ty(method_ty
);
519 // The index method always returns an `&T`, so
520 // dereference it to find the result type.
521 let elem_ty
= match ret_ty
.sty
{
522 ty
::TyRef(_
, mt
) => mt
.ty
,
524 debug
!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
530 // The call to index() returns a `&T` value, which
531 // is an rvalue. That is what we will be
533 let base_cmt
= self.cat_rvalue_node(expr
.id(), expr
.span(), ret_ty
);
534 self.cat_deref_common(expr
, base_cmt
, 1, elem_ty
, Some(context
), true)
537 self.cat_index(expr
, try
!(self.cat_expr(&**base
)), context
)
542 ast
::ExprPath(..) => {
543 let def
= self.tcx().def_map
.borrow().get(&expr
.id
).unwrap().full_def();
544 self.cat_def(expr
.id
, expr
.span
, expr_ty
, def
)
547 ast
::ExprParen(ref e
) => {
551 ast
::ExprAddrOf(..) | ast
::ExprCall(..) |
552 ast
::ExprAssign(..) | ast
::ExprAssignOp(..) |
553 ast
::ExprClosure(..) | ast
::ExprRet(..) |
554 ast
::ExprUnary(..) | ast
::ExprRange(..) |
555 ast
::ExprMethodCall(..) | ast
::ExprCast(..) |
556 ast
::ExprVec(..) | ast
::ExprTup(..) | ast
::ExprIf(..) |
557 ast
::ExprBinary(..) | ast
::ExprWhile(..) |
558 ast
::ExprBlock(..) | ast
::ExprLoop(..) | ast
::ExprMatch(..) |
559 ast
::ExprLit(..) | ast
::ExprBreak(..) | ast
::ExprMac(..) |
560 ast
::ExprAgain(..) | ast
::ExprStruct(..) | ast
::ExprRepeat(..) |
561 ast
::ExprInlineAsm(..) | ast
::ExprBox(..) => {
562 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
565 ast
::ExprIfLet(..) => {
566 self.tcx().sess
.span_bug(expr
.span
, "non-desugared ExprIfLet");
568 ast
::ExprWhileLet(..) => {
569 self.tcx().sess
.span_bug(expr
.span
, "non-desugared ExprWhileLet");
571 ast
::ExprForLoop(..) => {
572 self.tcx().sess
.span_bug(expr
.span
, "non-desugared ExprForLoop");
577 pub fn cat_def(&self,
582 -> McResult
<cmt
<'tcx
>> {
583 debug
!("cat_def: id={} expr={:?} def={:?}",
587 def
::DefStruct(..) | def
::DefVariant(..) | def
::DefConst(..) |
588 def
::DefAssociatedConst(..) | def
::DefFn(..) | def
::DefMethod(..) => {
589 Ok(self.cat_rvalue_node(id
, span
, expr_ty
))
591 def
::DefMod(_
) | def
::DefForeignMod(_
) | def
::DefUse(_
) |
592 def
::DefTrait(_
) | def
::DefTy(..) | def
::DefPrimTy(_
) |
593 def
::DefTyParam(..) | def
::DefRegion(_
) |
594 def
::DefLabel(_
) | def
::DefSelfTy(..) |
595 def
::DefAssociatedTy(..) => {
606 def
::DefStatic(_
, mutbl
) => {
611 mutbl
: if mutbl { McDeclared }
else { McImmutable}
,
617 def
::DefUpvar(var_id
, fn_node_id
) => {
618 let ty
= try
!(self.node_ty(fn_node_id
));
620 ty
::TyClosure(closure_id
, _
) => {
621 match self.typer
.closure_kind(closure_id
) {
623 self.cat_upvar(id
, span
, var_id
, fn_node_id
, kind
)
626 self.tcx().sess
.span_bug(
628 &*format
!("No closure kind for {:?}", closure_id
));
633 self.tcx().sess
.span_bug(
635 &format
!("Upvar of non-closure {} - {:?}",
642 def
::DefLocal(vid
) => {
647 mutbl
: MutabilityCategory
::from_local(self.tcx(), vid
),
655 // Categorize an upvar, complete with invisible derefs of closure
656 // environment and upvar reference as appropriate.
661 fn_node_id
: ast
::NodeId
,
662 kind
: ty
::ClosureKind
)
663 -> McResult
<cmt
<'tcx
>>
665 // An upvar can have up to 3 components. We translate first to a
666 // `cat_upvar`, which is itself a fiction -- it represents the reference to the
667 // field from the environment.
669 // `cat_upvar`. Next, we add a deref through the implicit
670 // environment pointer with an anonymous free region 'env and
671 // appropriate borrow kind for closure kinds that take self by
672 // reference. Finally, if the upvar was captured
673 // by-reference, we add a deref through that reference. The
674 // region of this reference is an inference variable 'up that
675 // was previously generated and recorded in the upvar borrow
676 // map. The borrow kind bk is inferred by based on how the
679 // This results in the following table for concrete closure
683 // ---------------+----------------------+-------------------------------
684 // Fn | copied -> &'env | upvar -> &'env -> &'up bk
685 // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
686 // FnOnce | copied | upvar -> &'up bk
688 let upvar_id
= ty
::UpvarId
{ var_id
: var_id
,
689 closure_expr_id
: fn_node_id
};
690 let var_ty
= try
!(self.node_ty(var_id
));
692 // Mutability of original variable itself
693 let var_mutbl
= MutabilityCategory
::from_local(self.tcx(), var_id
);
695 // Construct the upvar. This represents access to the field
696 // from the environment (perhaps we should eventually desugar
697 // this field further, but it will do for now).
698 let cmt_result
= cmt_
{
701 cat
: cat_upvar(Upvar {id: upvar_id, kind: kind}
),
707 // If this is a `FnMut` or `Fn` closure, then the above is
708 // conceptually a `&mut` or `&` reference, so we have to add a
710 let cmt_result
= match kind
{
711 ty
::FnOnceClosureKind
=> {
714 ty
::FnMutClosureKind
=> {
715 self.env_deref(id
, span
, upvar_id
, var_mutbl
, ty
::MutBorrow
, cmt_result
)
717 ty
::FnClosureKind
=> {
718 self.env_deref(id
, span
, upvar_id
, var_mutbl
, ty
::ImmBorrow
, cmt_result
)
722 // If this is a by-ref capture, then the upvar we loaded is
723 // actually a reference, so we have to add an implicit deref
725 let upvar_id
= ty
::UpvarId
{ var_id
: var_id
,
726 closure_expr_id
: fn_node_id
};
727 let upvar_capture
= self.typer
.upvar_capture(upvar_id
).unwrap();
728 let cmt_result
= match upvar_capture
{
729 ty
::UpvarCapture
::ByValue
=> {
732 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
733 let ptr
= BorrowedPtr(upvar_borrow
.kind
, upvar_borrow
.region
);
737 cat
: cat_deref(Rc
::new(cmt_result
), 0, ptr
),
738 mutbl
: MutabilityCategory
::from_borrow_kind(upvar_borrow
.kind
),
740 note
: NoteUpvarRef(upvar_id
)
745 let ret
= Rc
::new(cmt_result
);
746 debug
!("cat_upvar ret={:?}", ret
);
753 upvar_id
: ty
::UpvarId
,
754 upvar_mutbl
: MutabilityCategory
,
755 env_borrow_kind
: ty
::BorrowKind
,
756 cmt_result
: cmt_
<'tcx
>)
759 // Look up the node ID of the closure body so we can construct
760 // a free region within it
762 let fn_expr
= match self.tcx().map
.find(upvar_id
.closure_expr_id
) {
763 Some(ast_map
::NodeExpr(e
)) => e
,
768 ast
::ExprClosure(_
, _
, ref body
) => body
.id
,
773 // Region of environment pointer
774 let env_region
= ty
::ReFree(ty
::FreeRegion
{
775 // The environment of a closure is guaranteed to
776 // outlive any bindings introduced in the body of the
778 scope
: region
::DestructionScopeData
::new(fn_body_id
),
779 bound_region
: ty
::BrEnv
782 let env_ptr
= BorrowedPtr(env_borrow_kind
, env_region
);
784 let var_ty
= cmt_result
.ty
;
786 // We need to add the env deref. This means
787 // that the above is actually immutable and
788 // has a ref type. However, nothing should
789 // actually look at the type, so we can get
790 // away with stuffing a `TyError` in there
791 // instead of bothering to construct a proper
793 let cmt_result
= cmt_
{
795 ty
: self.tcx().types
.err
,
799 let mut deref_mutbl
= MutabilityCategory
::from_borrow_kind(env_borrow_kind
);
801 // Issue #18335. If variable is declared as immutable, override the
802 // mutability from the environment and substitute an `&T` anyway.
804 McImmutable
=> { deref_mutbl = McImmutable; }
805 McDeclared
| McInherited
=> { }
811 cat
: cat_deref(Rc
::new(cmt_result
), 0, env_ptr
),
814 note
: NoteClosureEnv(upvar_id
)
817 debug
!("env_deref ret {:?}", ret
);
822 /// Returns the lifetime of a temporary created by expr with id `id`.
823 /// This could be `'static` if `id` is part of a constant expression.
824 pub fn temporary_scope(&self, id
: ast
::NodeId
) -> ty
::Region
{
825 match self.typer
.temporary_scope(id
) {
826 Some(scope
) => ty
::ReScope(scope
),
831 pub fn cat_rvalue_node(&self,
836 let qualif
= self.tcx().const_qualif_map
.borrow().get(&id
).cloned()
837 .unwrap_or(check_const
::ConstQualif
::NOT_CONST
);
839 // Only promote `[T; 0]` before an RFC for rvalue promotions
841 let qualif
= match expr_ty
.sty
{
842 ty
::TyArray(_
, 0) => qualif
,
843 _
=> check_const
::ConstQualif
::NOT_CONST
846 // Compute maximum lifetime of this rvalue. This is 'static if
847 // we can promote to a constant, otherwise equal to enclosing temp
849 let re
= if qualif
.intersects(check_const
::ConstQualif
::NON_STATIC_BORROWS
) {
850 self.temporary_scope(id
)
854 let ret
= self.cat_rvalue(id
, span
, re
, expr_ty
);
855 debug
!("cat_rvalue_node ret {:?}", ret
);
859 pub fn cat_rvalue(&self,
862 temp_scope
: ty
::Region
,
863 expr_ty
: Ty
<'tcx
>) -> cmt
<'tcx
> {
864 let ret
= Rc
::new(cmt_
{
867 cat
:cat_rvalue(temp_scope
),
872 debug
!("cat_rvalue ret {:?}", ret
);
876 pub fn cat_field
<N
:ast_node
>(&self,
882 let ret
= Rc
::new(cmt_
{
885 mutbl
: base_cmt
.mutbl
.inherit(),
886 cat
: cat_interior(base_cmt
, InteriorField(NamedField(f_name
))),
890 debug
!("cat_field ret {:?}", ret
);
894 pub fn cat_tup_field
<N
:ast_node
>(&self,
900 let ret
= Rc
::new(cmt_
{
903 mutbl
: base_cmt
.mutbl
.inherit(),
904 cat
: cat_interior(base_cmt
, InteriorField(PositionalField(f_idx
))),
908 debug
!("cat_tup_field ret {:?}", ret
);
912 fn cat_deref
<N
:ast_node
>(&self,
916 deref_context
: DerefKindContext
)
917 -> McResult
<cmt
<'tcx
>> {
918 let method_call
= ty
::MethodCall
{
920 autoderef
: deref_cnt
as u32
922 let method_ty
= self.typer
.node_method_ty(method_call
);
924 debug
!("cat_deref: method_call={:?} method_ty={:?}",
925 method_call
, method_ty
.map(|ty
| ty
));
927 let base_cmt
= match method_ty
{
930 ty
::no_late_bound_regions(
931 self.tcx(), &ty
::ty_fn_ret(method_ty
)).unwrap().unwrap();
932 self.cat_rvalue_node(node
.id(), node
.span(), ref_ty
)
936 let base_cmt_ty
= base_cmt
.ty
;
937 match ty
::deref(base_cmt_ty
, true) {
939 let ret
= self.cat_deref_common(node
, base_cmt
, deref_cnt
,
942 /* implicit: */ false);
943 debug
!("cat_deref ret {:?}", ret
);
947 debug
!("Explicit deref of non-derefable type: {:?}",
954 fn cat_deref_common
<N
:ast_node
>(&self,
959 deref_context
: DerefKindContext
,
961 -> McResult
<cmt
<'tcx
>>
963 let (m
, cat
) = match try
!(deref_kind(base_cmt
.ty
, deref_context
)) {
965 let ptr
= if implicit
{
967 BorrowedPtr(bk
, r
) => Implicit(bk
, r
),
968 _
=> self.tcx().sess
.span_bug(node
.span(),
969 "Implicit deref of non-borrowed pointer")
974 // for unique ptrs, we inherit mutability from the
976 (MutabilityCategory
::from_pointer_kind(base_cmt
.mutbl
, ptr
),
977 cat_deref(base_cmt
, deref_cnt
, ptr
))
979 deref_interior(interior
) => {
980 (base_cmt
.mutbl
.inherit(), cat_interior(base_cmt
, interior
))
983 let ret
= Rc
::new(cmt_
{
991 debug
!("cat_deref_common ret {:?}", ret
);
995 pub fn cat_index
<N
:ast_node
>(&self,
997 mut base_cmt
: cmt
<'tcx
>,
998 context
: InteriorOffsetKind
)
999 -> McResult
<cmt
<'tcx
>> {
1000 //! Creates a cmt for an indexing operation (`[]`).
1002 //! One subtle aspect of indexing that may not be
1003 //! immediately obvious: for anything other than a fixed-length
1004 //! vector, an operation like `x[y]` actually consists of two
1005 //! disjoint (from the point of view of borrowck) operations.
1006 //! The first is a deref of `x` to create a pointer `p` that points
1007 //! at the first element in the array. The second operation is
1008 //! an index which adds `y*sizeof(T)` to `p` to obtain the
1009 //! pointer to `x[y]`. `cat_index` will produce a resulting
1010 //! cmt containing both this deref and the indexing,
1011 //! presuming that `base_cmt` is not of fixed-length type.
1014 //! - `elt`: the AST node being indexed
1015 //! - `base_cmt`: the cmt of `elt`
1017 let method_call
= ty
::MethodCall
::expr(elt
.id());
1018 let method_ty
= self.typer
.node_method_ty(method_call
);
1020 let element_ty
= match method_ty
{
1021 Some(method_ty
) => {
1022 let ref_ty
= self.overloaded_method_return_ty(method_ty
);
1023 base_cmt
= self.cat_rvalue_node(elt
.id(), elt
.span(), ref_ty
);
1025 // FIXME(#20649) -- why are we using the `self_ty` as the element type...?
1026 let self_ty
= ty
::ty_fn_sig(method_ty
).input(0);
1027 ty
::no_late_bound_regions(self.tcx(), &self_ty
).unwrap()
1030 match ty
::array_element_ty(self.tcx(), base_cmt
.ty
) {
1039 let m
= base_cmt
.mutbl
.inherit();
1040 let ret
= interior(elt
, base_cmt
.clone(), base_cmt
.ty
,
1041 m
, context
, element_ty
);
1042 debug
!("cat_index ret {:?}", ret
);
1045 fn interior
<'tcx
, N
: ast_node
>(elt
: &N
,
1048 mutbl
: MutabilityCategory
,
1049 context
: InteriorOffsetKind
,
1050 element_ty
: Ty
<'tcx
>) -> cmt
<'tcx
>
1052 let interior_elem
= InteriorElement(context
, element_kind(vec_ty
));
1056 cat
:cat_interior(of_cmt
, interior_elem
),
1064 // Takes either a vec or a reference to a vec and returns the cmt for the
1066 fn deref_vec
<N
:ast_node
>(&self,
1068 base_cmt
: cmt
<'tcx
>,
1069 context
: InteriorOffsetKind
)
1070 -> McResult
<cmt
<'tcx
>>
1072 let ret
= match try
!(deref_kind(base_cmt
.ty
, Some(context
))) {
1074 // for unique ptrs, we inherit mutability from the
1075 // owning reference.
1076 let m
= MutabilityCategory
::from_pointer_kind(base_cmt
.mutbl
, ptr
);
1078 // the deref is explicit in the resulting cmt
1082 cat
:cat_deref(base_cmt
.clone(), 0, ptr
),
1084 ty
: match ty
::deref(base_cmt
.ty
, false) {
1086 None
=> self.tcx().sess
.bug("Found non-derefable type")
1092 deref_interior(_
) => {
1096 debug
!("deref_vec ret {:?}", ret
);
1100 /// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is
1101 /// the pattern `Q`, returns:
1104 /// * the mutability and region of the slice `Q`
1106 /// These last two bits of info happen to be things that borrowck needs.
1107 pub fn cat_slice_pattern(&self,
1109 slice_pat
: &ast
::Pat
)
1110 -> McResult
<(cmt
<'tcx
>, ast
::Mutability
, ty
::Region
)> {
1111 let slice_ty
= try
!(self.node_ty(slice_pat
.id
));
1112 let (slice_mutbl
, slice_r
) = vec_slice_info(self.tcx(),
1115 let context
= InteriorOffsetKind
::Pattern
;
1116 let cmt_vec
= try
!(self.deref_vec(slice_pat
, vec_cmt
, context
));
1117 let cmt_slice
= try
!(self.cat_index(slice_pat
, cmt_vec
, context
));
1118 return Ok((cmt_slice
, slice_mutbl
, slice_r
));
1120 /// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
1121 /// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
1122 /// have to recurse through rptrs.
1123 fn vec_slice_info(tcx
: &ty
::ctxt
,
1126 -> (ast
::Mutability
, ty
::Region
) {
1127 match slice_ty
.sty
{
1128 ty
::TyRef(r
, ref mt
) => match mt
.ty
.sty
{
1129 ty
::TySlice(_
) => (mt
.mutbl
, *r
),
1130 _
=> vec_slice_info(tcx
, pat
, mt
.ty
),
1134 tcx
.sess
.span_bug(pat
.span
,
1135 "type of slice pattern is not a slice");
1141 pub fn cat_imm_interior
<N
:ast_node
>(&self,
1143 base_cmt
: cmt
<'tcx
>,
1144 interior_ty
: Ty
<'tcx
>,
1145 interior
: InteriorKind
)
1147 let ret
= Rc
::new(cmt_
{
1150 mutbl
: base_cmt
.mutbl
.inherit(),
1151 cat
: cat_interior(base_cmt
, interior
),
1155 debug
!("cat_imm_interior ret={:?}", ret
);
1159 pub fn cat_downcast
<N
:ast_node
>(&self,
1161 base_cmt
: cmt
<'tcx
>,
1162 downcast_ty
: Ty
<'tcx
>,
1163 variant_did
: ast
::DefId
)
1165 let ret
= Rc
::new(cmt_
{
1168 mutbl
: base_cmt
.mutbl
.inherit(),
1169 cat
: cat_downcast(base_cmt
, variant_did
),
1173 debug
!("cat_downcast ret={:?}", ret
);
1177 pub fn cat_pattern
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &ast
::Pat
, mut op
: F
) -> McResult
<()>
1178 where F
: FnMut(&MemCategorizationContext
<'t
, TYPER
>, cmt
<'tcx
>, &ast
::Pat
),
1180 self.cat_pattern_(cmt
, pat
, &mut op
)
1183 // FIXME(#19596) This is a workaround, but there should be a better way to do this
1184 fn cat_pattern_
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &ast
::Pat
, op
: &mut F
)
1186 where F
: FnMut(&MemCategorizationContext
<'t
, TYPER
>, cmt
<'tcx
>, &ast
::Pat
),
1188 // Here, `cmt` is the categorization for the value being
1189 // matched and pat is the pattern it is being matched against.
1191 // In general, the way that this works is that we walk down
1192 // the pattern, constructing a cmt that represents the path
1193 // that will be taken to reach the value being matched.
1195 // When we encounter named bindings, we take the cmt that has
1196 // been built up and pass it off to guarantee_valid() so that
1197 // we can be sure that the binding will remain valid for the
1198 // duration of the arm.
1200 // (*2) There is subtlety concerning the correspondence between
1201 // pattern ids and types as compared to *expression* ids and
1202 // types. This is explained briefly. on the definition of the
1203 // type `cmt`, so go off and read what it says there, then
1204 // come back and I'll dive into a bit more detail here. :) OK,
1207 // In general, the id of the cmt should be the node that
1208 // "produces" the value---patterns aren't executable code
1209 // exactly, but I consider them to "execute" when they match a
1210 // value, and I consider them to produce the value that was
1211 // matched. So if you have something like:
1218 // In this case, the cmt and the relevant ids would be:
1220 // CMT Id Type of Id Type of cmt
1223 // ^~~~~~~^ `x` from discr @@int @@int
1224 // ^~~~~~~~~~^ `@@y` pattern node @@int @int
1225 // ^~~~~~~~~~~~~^ `@y` pattern node @int int
1227 // You can see that the types of the id and the cmt are in
1228 // sync in the first line, because that id is actually the id
1229 // of an expression. But once we get to pattern ids, the types
1230 // step out of sync again. So you'll see below that we always
1231 // get the type of the *subpattern* and use that.
1233 debug
!("cat_pattern: {:?} cmt={:?}",
1237 (*op
)(self, cmt
.clone(), pat
);
1239 let opt_def
= self.tcx().def_map
.borrow().get(&pat
.id
).map(|d
| d
.full_def());
1241 // Note: This goes up here (rather than within the PatEnum arm
1242 // alone) because struct patterns can refer to struct types or
1243 // to struct variants within enums.
1244 let cmt
= match opt_def
{
1245 Some(def
::DefVariant(enum_did
, variant_did
, _
))
1246 // univariant enums do not need downcasts
1247 if !ty
::enum_is_univariant(self.tcx(), enum_did
) => {
1248 self.cat_downcast(pat
, cmt
.clone(), cmt
.ty
, variant_did
)
1254 ast
::PatWild(_
) => {
1258 ast
::PatEnum(_
, None
) => {
1261 ast
::PatEnum(_
, Some(ref subpats
)) => {
1263 Some(def
::DefVariant(..)) => {
1265 for (i
, subpat
) in subpats
.iter().enumerate() {
1266 let subpat_ty
= try
!(self.pat_ty(&**subpat
)); // see (*2)
1269 self.cat_imm_interior(
1270 pat
, cmt
.clone(), subpat_ty
,
1271 InteriorField(PositionalField(i
)));
1273 try
!(self.cat_pattern_(subcmt
, &**subpat
, op
));
1276 Some(def
::DefStruct(..)) => {
1277 for (i
, subpat
) in subpats
.iter().enumerate() {
1278 let subpat_ty
= try
!(self.pat_ty(&**subpat
)); // see (*2)
1280 self.cat_imm_interior(
1281 pat
, cmt
.clone(), subpat_ty
,
1282 InteriorField(PositionalField(i
)));
1283 try
!(self.cat_pattern_(cmt_field
, &**subpat
, op
));
1286 Some(def
::DefConst(..)) | Some(def
::DefAssociatedConst(..)) => {
1287 for subpat
in subpats
{
1288 try
!(self.cat_pattern_(cmt
.clone(), &**subpat
, op
));
1292 self.tcx().sess
.span_bug(
1294 "enum pattern didn't resolve to enum or struct");
1299 ast
::PatQPath(..) => {
1300 // Lone constant: ignore
1303 ast
::PatIdent(_
, _
, Some(ref subpat
)) => {
1304 try
!(self.cat_pattern_(cmt
, &**subpat
, op
));
1307 ast
::PatIdent(_
, _
, None
) => {
1308 // nullary variant or identifier: ignore
1311 ast
::PatStruct(_
, ref field_pats
, _
) => {
1312 // {f1: p1, ..., fN: pN}
1313 for fp
in field_pats
{
1314 let field_ty
= try
!(self.pat_ty(&*fp
.node
.pat
)); // see (*2)
1315 let cmt_field
= self.cat_field(pat
, cmt
.clone(), fp
.node
.ident
.name
, field_ty
);
1316 try
!(self.cat_pattern_(cmt_field
, &*fp
.node
.pat
, op
));
1320 ast
::PatTup(ref subpats
) => {
1322 for (i
, subpat
) in subpats
.iter().enumerate() {
1323 let subpat_ty
= try
!(self.pat_ty(&**subpat
)); // see (*2)
1325 self.cat_imm_interior(
1326 pat
, cmt
.clone(), subpat_ty
,
1327 InteriorField(PositionalField(i
)));
1328 try
!(self.cat_pattern_(subcmt
, &**subpat
, op
));
1332 ast
::PatBox(ref subpat
) | ast
::PatRegion(ref subpat
, _
) => {
1333 // box p1, &p1, &mut p1. we can ignore the mutability of
1334 // PatRegion since that information is already contained
1336 let subcmt
= try
!(self.cat_deref(pat
, cmt
, 0, None
));
1337 try
!(self.cat_pattern_(subcmt
, &**subpat
, op
));
1340 ast
::PatVec(ref before
, ref slice
, ref after
) => {
1341 let context
= InteriorOffsetKind
::Pattern
;
1342 let vec_cmt
= try
!(self.deref_vec(pat
, cmt
, context
));
1343 let elt_cmt
= try
!(self.cat_index(pat
, vec_cmt
, context
));
1344 for before_pat
in before
{
1345 try
!(self.cat_pattern_(elt_cmt
.clone(), &**before_pat
, op
));
1347 if let Some(ref slice_pat
) = *slice
{
1348 let slice_ty
= try
!(self.pat_ty(&**slice_pat
));
1349 let slice_cmt
= self.cat_rvalue_node(pat
.id(), pat
.span(), slice_ty
);
1350 try
!(self.cat_pattern_(slice_cmt
, &**slice_pat
, op
));
1352 for after_pat
in after
{
1353 try
!(self.cat_pattern_(elt_cmt
.clone(), &**after_pat
, op
));
1357 ast
::PatLit(_
) | ast
::PatRange(_
, _
) => {
1362 self.tcx().sess
.span_bug(pat
.span
, "unexpanded macro");
1369 fn overloaded_method_return_ty(&self,
1370 method_ty
: Ty
<'tcx
>)
1373 // When we process an overloaded `*` or `[]` etc, we often
1374 // need to extract the return type of the method. These method
1375 // types are generated by method resolution and always have
1376 // all late-bound regions fully instantiated, so we just want
1377 // to skip past the binder.
1378 ty
::no_late_bound_regions(self.tcx(), &ty
::ty_fn_ret(method_ty
))
1380 .unwrap() // overloaded ops do not diverge, either
1384 #[derive(Clone, Debug)]
1385 pub enum Aliasability
{
1386 FreelyAliasable(AliasableReason
),
1388 ImmutableUnique(Box
<Aliasability
>),
1391 #[derive(Copy, Clone, Debug)]
1392 pub enum AliasableReason
{
1394 AliasableClosure(ast
::NodeId
), // Aliasable due to capture Fn closure env
1396 UnaliasableImmutable
, // Created as needed upon seeing ImmutableUnique
1401 impl<'tcx
> cmt_
<'tcx
> {
1402 pub fn guarantor(&self) -> cmt
<'tcx
> {
1403 //! Returns `self` after stripping away any derefs or
1404 //! interior content. The return value is basically the `cmt` which
1405 //! determines how long the value in `self` remains live.
1411 cat_deref(_
, _
, UnsafePtr(..)) |
1412 cat_deref(_
, _
, BorrowedPtr(..)) |
1413 cat_deref(_
, _
, Implicit(..)) |
1415 Rc
::new((*self).clone())
1417 cat_downcast(ref b
, _
) |
1418 cat_interior(ref b
, _
) |
1419 cat_deref(ref b
, _
, Unique
) => {
1425 /// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
1426 pub fn freely_aliasable(&self, ctxt
: &ty
::ctxt
<'tcx
>)
1428 // Maybe non-obvious: copied upvars can only be considered
1429 // non-aliasable in once closures, since any other kind can be
1430 // aliased and eventually recused.
1433 cat_deref(ref b
, _
, BorrowedPtr(ty
::MutBorrow
, _
)) |
1434 cat_deref(ref b
, _
, Implicit(ty
::MutBorrow
, _
)) |
1435 cat_deref(ref b
, _
, BorrowedPtr(ty
::UniqueImmBorrow
, _
)) |
1436 cat_deref(ref b
, _
, Implicit(ty
::UniqueImmBorrow
, _
)) |
1437 cat_downcast(ref b
, _
) |
1438 cat_interior(ref b
, _
) => {
1439 // Aliasability depends on base cmt
1440 b
.freely_aliasable(ctxt
)
1443 cat_deref(ref b
, _
, Unique
) => {
1444 let sub
= b
.freely_aliasable(ctxt
);
1445 if b
.mutbl
.is_mutable() {
1446 // Aliasability depends on base cmt alone
1449 // Do not allow mutation through an immutable box.
1450 ImmutableUnique(Box
::new(sub
))
1457 cat_deref(_
, _
, UnsafePtr(..)) => { // yes, it's aliasable, but...
1461 cat_static_item(..) => {
1462 if self.mutbl
.is_mutable() {
1463 FreelyAliasable(AliasableStaticMut
)
1465 FreelyAliasable(AliasableStatic
)
1469 cat_deref(ref base
, _
, BorrowedPtr(ty
::ImmBorrow
, _
)) |
1470 cat_deref(ref base
, _
, Implicit(ty
::ImmBorrow
, _
)) => {
1472 cat_upvar(Upvar{ id, .. }
) =>
1473 FreelyAliasable(AliasableClosure(id
.closure_expr_id
)),
1474 _
=> FreelyAliasable(AliasableBorrowed
)
1480 // Digs down through one or two layers of deref and grabs the cmt
1481 // for the upvar if a note indicates there is one.
1482 pub fn upvar(&self) -> Option
<cmt
<'tcx
>> {
1484 NoteClosureEnv(..) | NoteUpvarRef(..) => {
1485 Some(match self.cat
{
1486 cat_deref(ref inner
, _
, _
) => {
1488 cat_deref(ref inner
, _
, _
) => inner
.clone(),
1489 cat_upvar(..) => inner
.clone(),
1501 pub fn descriptive_string(&self, tcx
: &ty
::ctxt
) -> String
{
1503 cat_static_item
=> {
1504 "static item".to_string()
1507 "non-lvalue".to_string()
1510 match tcx
.map
.find(vid
) {
1511 Some(ast_map
::NodeArg(_
)) => {
1512 "argument".to_string()
1514 _
=> "local variable".to_string()
1517 cat_deref(_
, _
, pk
) => {
1518 let upvar
= self.upvar();
1519 match upvar
.as_ref().map(|i
| &i
.cat
) {
1520 Some(&cat_upvar(ref var
)) => {
1523 Some(_
) => unreachable
!(),
1527 format
!("indexed content")
1530 format
!("`Box` content")
1533 format
!("dereference of raw pointer")
1535 BorrowedPtr(..) => {
1536 format
!("borrowed content")
1542 cat_interior(_
, InteriorField(NamedField(_
))) => {
1545 cat_interior(_
, InteriorField(PositionalField(_
))) => {
1546 "anonymous field".to_string()
1548 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1550 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1552 "indexed content".to_string()
1554 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1556 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1558 "pattern-bound indexed content".to_string()
1560 cat_upvar(ref var
) => {
1563 cat_downcast(ref cmt
, _
) => {
1564 cmt
.descriptive_string(tcx
)
1570 impl<'tcx
> fmt
::Debug
for cmt_
<'tcx
> {
1571 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1572 write
!(f
, "{{{:?} id:{} m:{:?} ty:{:?}}}",
1580 impl<'tcx
> fmt
::Debug
for categorization
<'tcx
> {
1581 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1583 cat_static_item
=> write
!(f
, "static"),
1584 cat_rvalue(r
) => write
!(f
, "rvalue({:?})", r
),
1586 let name
= ty
::tls
::with(|tcx
| ty
::local_var_name_str(tcx
, id
));
1587 write
!(f
, "local({})", name
)
1589 cat_upvar(upvar
) => {
1590 write
!(f
, "upvar({:?})", upvar
)
1592 cat_deref(ref cmt
, derefs
, ptr
) => {
1593 write
!(f
, "{:?}-{:?}{}->", cmt
.cat
, ptr
, derefs
)
1595 cat_interior(ref cmt
, interior
) => {
1596 write
!(f
, "{:?}.{:?}", cmt
.cat
, interior
)
1598 cat_downcast(ref cmt
, _
) => {
1599 write
!(f
, "{:?}->(enum)", cmt
.cat
)
1605 pub fn ptr_sigil(ptr
: PointerKind
) -> &'
static str {
1608 BorrowedPtr(ty
::ImmBorrow
, _
) |
1609 Implicit(ty
::ImmBorrow
, _
) => "&",
1610 BorrowedPtr(ty
::MutBorrow
, _
) |
1611 Implicit(ty
::MutBorrow
, _
) => "&mut",
1612 BorrowedPtr(ty
::UniqueImmBorrow
, _
) |
1613 Implicit(ty
::UniqueImmBorrow
, _
) => "&unique",
1614 UnsafePtr(_
) => "*",
1618 impl fmt
::Debug
for PointerKind
{
1619 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1621 Unique
=> write
!(f
, "Box"),
1622 BorrowedPtr(ty
::ImmBorrow
, ref r
) |
1623 Implicit(ty
::ImmBorrow
, ref r
) => {
1624 write
!(f
, "&{:?}", r
)
1626 BorrowedPtr(ty
::MutBorrow
, ref r
) |
1627 Implicit(ty
::MutBorrow
, ref r
) => {
1628 write
!(f
, "&{:?} mut", r
)
1630 BorrowedPtr(ty
::UniqueImmBorrow
, ref r
) |
1631 Implicit(ty
::UniqueImmBorrow
, ref r
) => {
1632 write
!(f
, "&{:?} uniq", r
)
1634 UnsafePtr(_
) => write
!(f
, "*")
1639 impl fmt
::Debug
for InteriorKind
{
1640 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1642 InteriorField(NamedField(fld
)) => write
!(f
, "{}", fld
),
1643 InteriorField(PositionalField(i
)) => write
!(f
, "#{}", i
),
1644 InteriorElement(..) => write
!(f
, "[]"),
1649 fn element_kind(t
: Ty
) -> ElementKind
{
1651 ty
::TyRef(_
, ty
::mt{ty, ..}
) |
1652 ty
::TyBox(ty
) => match ty
.sty
{
1653 ty
::TySlice(_
) => VecElement
,
1656 ty
::TyArray(..) | ty
::TySlice(_
) => VecElement
,
1661 impl fmt
::Debug
for Upvar
{
1662 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1663 write
!(f
, "{:?}/{:?}", self.id
, self.kind
)
1667 impl fmt
::Display
for Upvar
{
1668 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1669 let kind
= match self.kind
{
1670 ty
::FnClosureKind
=> "Fn",
1671 ty
::FnMutClosureKind
=> "FnMut",
1672 ty
::FnOnceClosureKind
=> "FnOnce",
1674 write
!(f
, "captured outer variable in an `{}` closure", kind
)