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 `Categorization::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
::*;
72 use self::Aliasability
::*;
74 use hir
::def_id
::DefId
;
75 use hir
::map
as ast_map
;
77 use middle
::const_qualif
::ConstQualif
;
80 use ty
::{self, Ty, TyCtxt}
;
82 use hir
::{MutImmutable, MutMutable, PatKind}
;
83 use hir
::pat_util
::EnumerateAndAdjustIterator
;
91 #[derive(Clone, PartialEq)]
92 pub enum Categorization
<'tcx
> {
93 Rvalue(ty
::Region
), // temporary val, argument is its scope
95 Upvar(Upvar
), // upvar referenced by closure env
96 Local(ast
::NodeId
), // local variable
97 Deref(cmt
<'tcx
>, usize, PointerKind
), // deref of a ptr
98 Interior(cmt
<'tcx
>, InteriorKind
), // something interior: field, tuple, etc
99 Downcast(cmt
<'tcx
>, DefId
), // selects a particular enum variant (*1)
101 // (*1) downcast is only required if the enum has more than one variant
104 // Represents any kind of upvar
105 #[derive(Clone, Copy, PartialEq)]
108 pub kind
: ty
::ClosureKind
111 // different kinds of pointers:
112 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
113 pub enum PointerKind
{
118 BorrowedPtr(ty
::BorrowKind
, ty
::Region
),
121 UnsafePtr(hir
::Mutability
),
123 /// Implicit deref of the `&T` that results from an overloaded index `[]`.
124 Implicit(ty
::BorrowKind
, ty
::Region
),
127 // We use the term "interior" to mean "something reachable from the
128 // base without a pointer dereference", e.g. a field
129 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
130 pub enum InteriorKind
{
131 InteriorField(FieldName
),
132 InteriorElement(InteriorOffsetKind
, ElementKind
),
135 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
137 NamedField(ast
::Name
),
138 PositionalField(usize)
141 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
142 pub enum InteriorOffsetKind
{
143 Index
, // e.g. `array_expr[index_expr]`
144 Pattern
, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
147 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
148 pub enum ElementKind
{
153 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
154 pub enum MutabilityCategory
{
155 McImmutable
, // Immutable.
156 McDeclared
, // Directly declared as mutable.
157 McInherited
, // Inherited from the fact that owner is mutable.
160 // A note about the provenance of a `cmt`. This is used for
161 // special-case handling of upvars such as mutability inference.
162 // Upvar categorization can generate a variable number of nested
163 // derefs. The note allows detecting them without deep pattern
164 // matching on the categorization.
165 #[derive(Clone, Copy, PartialEq, Debug)]
167 NoteClosureEnv(ty
::UpvarId
), // Deref through closure env
168 NoteUpvarRef(ty
::UpvarId
), // Deref through by-ref upvar
169 NoteNone
// Nothing special
172 // `cmt`: "Category, Mutability, and Type".
174 // a complete categorization of a value indicating where it originated
175 // and how it is located, as well as the mutability of the memory in
176 // which the value is stored.
178 // *WARNING* The field `cmt.type` is NOT necessarily the same as the
179 // result of `node_id_to_type(cmt.id)`. This is because the `id` is
180 // always the `id` of the node producing the type; in an expression
181 // like `*x`, the type of this deref node is the deref'd type (`T`),
182 // but in a pattern like `@x`, the `@x` pattern is again a
183 // dereference, but its type is the type *before* the dereference
184 // (`@T`). So use `cmt.ty` to find the type of the value in a consistent
185 // fashion. For more details, see the method `cat_pattern`
186 #[derive(Clone, PartialEq)]
187 pub struct cmt_
<'tcx
> {
188 pub id
: ast
::NodeId
, // id of expr/pat producing this value
189 pub span
: Span
, // span of same expr/pat
190 pub cat
: Categorization
<'tcx
>, // categorization of expr
191 pub mutbl
: MutabilityCategory
, // mutability of expr as lvalue
192 pub ty
: Ty
<'tcx
>, // type of the expr (*see WARNING above*)
193 pub note
: Note
, // Note about the provenance of this cmt
196 pub type cmt
<'tcx
> = Rc
<cmt_
<'tcx
>>;
198 // We pun on *T to mean both actual deref of a ptr as well
199 // as accessing of components:
200 #[derive(Copy, Clone)]
201 pub enum deref_kind
{
202 deref_ptr(PointerKind
),
203 deref_interior(InteriorKind
),
206 type DerefKindContext
= Option
<InteriorOffsetKind
>;
208 // Categorizes a derefable type. Note that we include vectors and strings as
209 // derefable (we model an index as the combination of a deref and then a
210 // pointer adjustment).
211 fn deref_kind(t
: Ty
, context
: DerefKindContext
) -> McResult
<deref_kind
> {
214 Ok(deref_ptr(Unique
))
217 ty
::TyRef(r
, mt
) => {
218 let kind
= ty
::BorrowKind
::from_mutbl(mt
.mutbl
);
219 Ok(deref_ptr(BorrowedPtr(kind
, *r
)))
222 ty
::TyRawPtr(ref mt
) => {
223 Ok(deref_ptr(UnsafePtr(mt
.mutbl
)))
227 ty
::TyStruct(..) => { // newtype
228 Ok(deref_interior(InteriorField(PositionalField(0))))
231 ty
::TyArray(_
, _
) | ty
::TySlice(_
) => {
232 // no deref of indexed content without supplying InteriorOffsetKind
233 if let Some(context
) = context
{
234 Ok(deref_interior(InteriorElement(context
, ElementKind
::VecElement
)))
245 fn id(&self) -> ast
::NodeId
;
246 fn span(&self) -> Span
;
249 impl ast_node
for hir
::Expr
{
250 fn id(&self) -> ast
::NodeId { self.id }
251 fn span(&self) -> Span { self.span }
254 impl ast_node
for hir
::Pat
{
255 fn id(&self) -> ast
::NodeId { self.id }
256 fn span(&self) -> Span { self.span }
259 #[derive(Copy, Clone)]
260 pub struct MemCategorizationContext
<'a
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
> {
261 pub infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
262 options
: MemCategorizationOptions
,
265 #[derive(Copy, Clone, Default)]
266 pub struct MemCategorizationOptions
{
267 // If true, then when analyzing a closure upvar, if the closure
268 // has a missing kind, we treat it like a Fn closure. When false,
269 // we ICE if the closure has a missing kind. Should be false
270 // except during closure kind inference. It is used by the
271 // mem-categorization code to be able to have stricter assertions
272 // (which are always true except during upvar inference).
273 pub during_closure_kind_inference
: bool
,
276 pub type McResult
<T
> = Result
<T
, ()>;
278 impl MutabilityCategory
{
279 pub fn from_mutbl(m
: hir
::Mutability
) -> MutabilityCategory
{
281 MutImmutable
=> McImmutable
,
282 MutMutable
=> McDeclared
284 debug
!("MutabilityCategory::{}({:?}) => {:?}",
285 "from_mutbl", m
, ret
);
289 pub fn from_borrow_kind(borrow_kind
: ty
::BorrowKind
) -> MutabilityCategory
{
290 let ret
= match borrow_kind
{
291 ty
::ImmBorrow
=> McImmutable
,
292 ty
::UniqueImmBorrow
=> McImmutable
,
293 ty
::MutBorrow
=> McDeclared
,
295 debug
!("MutabilityCategory::{}({:?}) => {:?}",
296 "from_borrow_kind", borrow_kind
, ret
);
300 fn from_pointer_kind(base_mutbl
: MutabilityCategory
,
301 ptr
: PointerKind
) -> MutabilityCategory
{
302 let ret
= match ptr
{
306 BorrowedPtr(borrow_kind
, _
) | Implicit(borrow_kind
, _
) => {
307 MutabilityCategory
::from_borrow_kind(borrow_kind
)
310 MutabilityCategory
::from_mutbl(m
)
313 debug
!("MutabilityCategory::{}({:?}, {:?}) => {:?}",
314 "from_pointer_kind", base_mutbl
, ptr
, ret
);
318 fn from_local(tcx
: TyCtxt
, id
: ast
::NodeId
) -> MutabilityCategory
{
319 let ret
= match tcx
.map
.get(id
) {
320 ast_map
::NodeLocal(p
) => match p
.node
{
321 PatKind
::Binding(bind_mode
, _
, _
) => {
322 if bind_mode
== hir
::BindByValue(hir
::MutMutable
) {
328 _
=> span_bug
!(p
.span
, "expected identifier pattern")
330 _
=> span_bug
!(tcx
.map
.span(id
), "expected identifier pattern")
332 debug
!("MutabilityCategory::{}(tcx, id={:?}) => {:?}",
333 "from_local", id
, ret
);
337 pub fn inherit(&self) -> MutabilityCategory
{
338 let ret
= match *self {
339 McImmutable
=> McImmutable
,
340 McDeclared
=> McInherited
,
341 McInherited
=> McInherited
,
343 debug
!("{:?}.inherit() => {:?}", self, ret
);
347 pub fn is_mutable(&self) -> bool
{
348 let ret
= match *self {
349 McImmutable
=> false,
353 debug
!("{:?}.is_mutable() => {:?}", self, ret
);
357 pub fn is_immutable(&self) -> bool
{
358 let ret
= match *self {
360 McDeclared
| McInherited
=> false
362 debug
!("{:?}.is_immutable() => {:?}", self, ret
);
366 pub fn to_user_str(&self) -> &'
static str {
368 McDeclared
| McInherited
=> "mutable",
369 McImmutable
=> "immutable",
374 impl<'a
, 'gcx
, 'tcx
> MemCategorizationContext
<'a
, 'gcx
, 'tcx
> {
375 pub fn new(infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>)
376 -> MemCategorizationContext
<'a
, 'gcx
, 'tcx
> {
377 MemCategorizationContext
::with_options(infcx
, MemCategorizationOptions
::default())
380 pub fn with_options(infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
381 options
: MemCategorizationOptions
)
382 -> MemCategorizationContext
<'a
, 'gcx
, 'tcx
> {
383 MemCategorizationContext
{
389 fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
> {
393 fn expr_ty(&self, expr
: &hir
::Expr
) -> McResult
<Ty
<'tcx
>> {
394 match self.infcx
.node_ty(expr
.id
) {
397 debug
!("expr_ty({:?}) yielded Err", expr
);
403 fn expr_ty_adjusted(&self, expr
: &hir
::Expr
) -> McResult
<Ty
<'tcx
>> {
404 let unadjusted_ty
= self.expr_ty(expr
)?
;
405 Ok(unadjusted_ty
.adjust(
406 self.tcx(), expr
.span
, expr
.id
,
407 self.infcx
.adjustments().get(&expr
.id
),
408 |method_call
| self.infcx
.node_method_ty(method_call
)))
411 fn node_ty(&self, id
: ast
::NodeId
) -> McResult
<Ty
<'tcx
>> {
412 self.infcx
.node_ty(id
)
415 fn pat_ty(&self, pat
: &hir
::Pat
) -> McResult
<Ty
<'tcx
>> {
416 let base_ty
= self.infcx
.node_ty(pat
.id
)?
;
417 // FIXME (Issue #18207): This code detects whether we are
418 // looking at a `ref x`, and if so, figures out what the type
419 // *being borrowed* is. But ideally we would put in a more
420 // fundamental fix to this conflated use of the node id.
421 let ret_ty
= match pat
.node
{
422 PatKind
::Binding(hir
::BindByRef(_
), _
, _
) => {
423 // a bind-by-ref means that the base_ty will be the type of the ident itself,
424 // but what we want here is the type of the underlying value being borrowed.
425 // So peel off one-level, turning the &T into T.
426 match base_ty
.builtin_deref(false, ty
::NoPreference
) {
428 None
=> { return Err(()); }
433 debug
!("pat_ty(pat={:?}) base_ty={:?} ret_ty={:?}",
434 pat
, base_ty
, ret_ty
);
438 pub fn cat_expr(&self, expr
: &hir
::Expr
) -> McResult
<cmt
<'tcx
>> {
439 match self.infcx
.adjustments().get(&expr
.id
) {
442 self.cat_expr_unadjusted(expr
)
445 Some(adjustment
) => {
447 adjustment
::AdjustDerefRef(
448 adjustment
::AutoDerefRef
{
449 autoref
: None
, unsize
: None
, autoderefs
, ..}) => {
450 // Equivalent to *expr or something similar.
451 self.cat_expr_autoderefd(expr
, autoderefs
)
454 adjustment
::AdjustNeverToAny(..) |
455 adjustment
::AdjustReifyFnPointer
|
456 adjustment
::AdjustUnsafeFnPointer
|
457 adjustment
::AdjustMutToConstPointer
|
458 adjustment
::AdjustDerefRef(_
) => {
459 debug
!("cat_expr({:?}): {:?}",
462 // Result is an rvalue.
463 let expr_ty
= self.expr_ty_adjusted(expr
)?
;
464 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
471 pub fn cat_expr_autoderefd(&self,
474 -> McResult
<cmt
<'tcx
>> {
475 let mut cmt
= self.cat_expr_unadjusted(expr
)?
;
476 debug
!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
479 for deref
in 1..autoderefs
+ 1 {
480 cmt
= self.cat_deref(expr
, cmt
, deref
, None
)?
;
485 pub fn cat_expr_unadjusted(&self, expr
: &hir
::Expr
) -> McResult
<cmt
<'tcx
>> {
486 debug
!("cat_expr: id={} expr={:?}", expr
.id
, expr
);
488 let expr_ty
= self.expr_ty(expr
)?
;
490 hir
::ExprUnary(hir
::UnDeref
, ref e_base
) => {
491 let base_cmt
= self.cat_expr(&e_base
)?
;
492 self.cat_deref(expr
, base_cmt
, 0, None
)
495 hir
::ExprField(ref base
, f_name
) => {
496 let base_cmt
= self.cat_expr(&base
)?
;
497 debug
!("cat_expr(cat_field): id={} expr={:?} base={:?}",
501 Ok(self.cat_field(expr
, base_cmt
, f_name
.node
, expr_ty
))
504 hir
::ExprTupField(ref base
, idx
) => {
505 let base_cmt
= self.cat_expr(&base
)?
;
506 Ok(self.cat_tup_field(expr
, base_cmt
, idx
.node
, expr_ty
))
509 hir
::ExprIndex(ref base
, _
) => {
510 let method_call
= ty
::MethodCall
::expr(expr
.id());
511 let context
= InteriorOffsetKind
::Index
;
512 match self.infcx
.node_method_ty(method_call
) {
514 // If this is an index implemented by a method call, then it
515 // will include an implicit deref of the result.
516 let ret_ty
= self.overloaded_method_return_ty(method_ty
);
518 // The index method always returns an `&T`, so
519 // dereference it to find the result type.
520 let elem_ty
= match ret_ty
.sty
{
521 ty
::TyRef(_
, mt
) => mt
.ty
,
523 debug
!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
529 // The call to index() returns a `&T` value, which
530 // is an rvalue. That is what we will be
532 let base_cmt
= self.cat_rvalue_node(expr
.id(), expr
.span(), ret_ty
);
533 self.cat_deref_common(expr
, base_cmt
, 1, elem_ty
, Some(context
), true)
536 self.cat_index(expr
, self.cat_expr(&base
)?
, context
)
541 hir
::ExprPath(..) => {
542 self.cat_def(expr
.id
, expr
.span
, expr_ty
, self.tcx().expect_def(expr
.id
))
545 hir
::ExprType(ref e
, _
) => {
549 hir
::ExprAddrOf(..) | hir
::ExprCall(..) |
550 hir
::ExprAssign(..) | hir
::ExprAssignOp(..) |
551 hir
::ExprClosure(..) | hir
::ExprRet(..) |
553 hir
::ExprMethodCall(..) | hir
::ExprCast(..) |
554 hir
::ExprVec(..) | hir
::ExprTup(..) | hir
::ExprIf(..) |
555 hir
::ExprBinary(..) | hir
::ExprWhile(..) |
556 hir
::ExprBlock(..) | hir
::ExprLoop(..) | hir
::ExprMatch(..) |
557 hir
::ExprLit(..) | hir
::ExprBreak(..) |
558 hir
::ExprAgain(..) | hir
::ExprStruct(..) | hir
::ExprRepeat(..) |
559 hir
::ExprInlineAsm(..) | hir
::ExprBox(..) => {
560 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
565 pub fn cat_def(&self,
570 -> McResult
<cmt
<'tcx
>> {
571 debug
!("cat_def: id={} expr={:?} def={:?}",
575 Def
::Struct(..) | Def
::Variant(..) | Def
::Const(..) |
576 Def
::AssociatedConst(..) | Def
::Fn(..) | Def
::Method(..) => {
577 Ok(self.cat_rvalue_node(id
, span
, expr_ty
))
580 Def
::Mod(_
) | Def
::ForeignMod(_
) |
581 Def
::Trait(_
) | Def
::Enum(..) | Def
::TyAlias(..) | Def
::PrimTy(_
) |
583 Def
::Label(_
) | Def
::SelfTy(..) |
584 Def
::AssociatedTy(..) => {
585 span_bug
!(span
, "Unexpected definition in \
586 memory categorization: {:?}", def
);
589 Def
::Static(_
, mutbl
) => {
593 cat
:Categorization
::StaticItem
,
594 mutbl
: if mutbl { McDeclared }
else { McImmutable}
,
600 Def
::Upvar(_
, var_id
, _
, fn_node_id
) => {
601 let ty
= self.node_ty(fn_node_id
)?
;
603 ty
::TyClosure(closure_id
, _
) => {
604 match self.infcx
.closure_kind(closure_id
) {
606 self.cat_upvar(id
, span
, var_id
, fn_node_id
, kind
)
609 if !self.options
.during_closure_kind_inference
{
612 "No closure kind for {:?}",
616 // during closure kind inference, we
617 // don't know the closure kind yet, but
618 // it's ok because we detect that we are
619 // accessing an upvar and handle that
620 // case specially anyhow. Use Fn
622 self.cat_upvar(id
, span
, var_id
, fn_node_id
, ty
::ClosureKind
::Fn
)
629 "Upvar of non-closure {} - {:?}",
636 Def
::Local(_
, vid
) => {
640 cat
: Categorization
::Local(vid
),
641 mutbl
: MutabilityCategory
::from_local(self.tcx(), vid
),
647 Def
::Err
=> bug
!("Def::Err in memory categorization")
651 // Categorize an upvar, complete with invisible derefs of closure
652 // environment and upvar reference as appropriate.
657 fn_node_id
: ast
::NodeId
,
658 kind
: ty
::ClosureKind
)
659 -> McResult
<cmt
<'tcx
>>
661 // An upvar can have up to 3 components. We translate first to a
662 // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the
663 // field from the environment.
665 // `Categorization::Upvar`. Next, we add a deref through the implicit
666 // environment pointer with an anonymous free region 'env and
667 // appropriate borrow kind for closure kinds that take self by
668 // reference. Finally, if the upvar was captured
669 // by-reference, we add a deref through that reference. The
670 // region of this reference is an inference variable 'up that
671 // was previously generated and recorded in the upvar borrow
672 // map. The borrow kind bk is inferred by based on how the
675 // This results in the following table for concrete closure
679 // ---------------+----------------------+-------------------------------
680 // Fn | copied -> &'env | upvar -> &'env -> &'up bk
681 // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
682 // FnOnce | copied | upvar -> &'up bk
684 let upvar_id
= ty
::UpvarId
{ var_id
: var_id
,
685 closure_expr_id
: fn_node_id
};
686 let var_ty
= self.node_ty(var_id
)?
;
688 // Mutability of original variable itself
689 let var_mutbl
= MutabilityCategory
::from_local(self.tcx(), var_id
);
691 // Construct the upvar. This represents access to the field
692 // from the environment (perhaps we should eventually desugar
693 // this field further, but it will do for now).
694 let cmt_result
= cmt_
{
697 cat
: Categorization
::Upvar(Upvar {id: upvar_id, kind: kind}
),
703 // If this is a `FnMut` or `Fn` closure, then the above is
704 // conceptually a `&mut` or `&` reference, so we have to add a
706 let cmt_result
= match kind
{
707 ty
::ClosureKind
::FnOnce
=> {
710 ty
::ClosureKind
::FnMut
=> {
711 self.env_deref(id
, span
, upvar_id
, var_mutbl
, ty
::MutBorrow
, cmt_result
)
713 ty
::ClosureKind
::Fn
=> {
714 self.env_deref(id
, span
, upvar_id
, var_mutbl
, ty
::ImmBorrow
, cmt_result
)
718 // If this is a by-ref capture, then the upvar we loaded is
719 // actually a reference, so we have to add an implicit deref
721 let upvar_id
= ty
::UpvarId
{ var_id
: var_id
,
722 closure_expr_id
: fn_node_id
};
723 let upvar_capture
= self.infcx
.upvar_capture(upvar_id
).unwrap();
724 let cmt_result
= match upvar_capture
{
725 ty
::UpvarCapture
::ByValue
=> {
728 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
729 let ptr
= BorrowedPtr(upvar_borrow
.kind
, upvar_borrow
.region
);
733 cat
: Categorization
::Deref(Rc
::new(cmt_result
), 0, ptr
),
734 mutbl
: MutabilityCategory
::from_borrow_kind(upvar_borrow
.kind
),
736 note
: NoteUpvarRef(upvar_id
)
741 let ret
= Rc
::new(cmt_result
);
742 debug
!("cat_upvar ret={:?}", ret
);
749 upvar_id
: ty
::UpvarId
,
750 upvar_mutbl
: MutabilityCategory
,
751 env_borrow_kind
: ty
::BorrowKind
,
752 cmt_result
: cmt_
<'tcx
>)
755 // Look up the node ID of the closure body so we can construct
756 // a free region within it
758 let fn_expr
= match self.tcx().map
.find(upvar_id
.closure_expr_id
) {
759 Some(ast_map
::NodeExpr(e
)) => e
,
764 hir
::ExprClosure(_
, _
, ref body
, _
) => body
.id
,
769 // Region of environment pointer
770 let env_region
= ty
::ReFree(ty
::FreeRegion
{
771 // The environment of a closure is guaranteed to
772 // outlive any bindings introduced in the body of the
774 scope
: self.tcx().region_maps
.item_extent(fn_body_id
),
775 bound_region
: ty
::BrEnv
778 let env_ptr
= BorrowedPtr(env_borrow_kind
, env_region
);
780 let var_ty
= cmt_result
.ty
;
782 // We need to add the env deref. This means
783 // that the above is actually immutable and
784 // has a ref type. However, nothing should
785 // actually look at the type, so we can get
786 // away with stuffing a `TyError` in there
787 // instead of bothering to construct a proper
789 let cmt_result
= cmt_
{
791 ty
: self.tcx().types
.err
,
795 let mut deref_mutbl
= MutabilityCategory
::from_borrow_kind(env_borrow_kind
);
797 // Issue #18335. If variable is declared as immutable, override the
798 // mutability from the environment and substitute an `&T` anyway.
800 McImmutable
=> { deref_mutbl = McImmutable; }
801 McDeclared
| McInherited
=> { }
807 cat
: Categorization
::Deref(Rc
::new(cmt_result
), 0, env_ptr
),
810 note
: NoteClosureEnv(upvar_id
)
813 debug
!("env_deref ret {:?}", ret
);
818 /// Returns the lifetime of a temporary created by expr with id `id`.
819 /// This could be `'static` if `id` is part of a constant expression.
820 pub fn temporary_scope(&self, id
: ast
::NodeId
) -> ty
::Region
{
821 match self.infcx
.temporary_scope(id
) {
822 Some(scope
) => ty
::ReScope(scope
),
827 pub fn cat_rvalue_node(&self,
832 let qualif
= self.tcx().const_qualif_map
.borrow().get(&id
).cloned()
833 .unwrap_or(ConstQualif
::NOT_CONST
);
835 // Only promote `[T; 0]` before an RFC for rvalue promotions
837 let qualif
= match expr_ty
.sty
{
838 ty
::TyArray(_
, 0) => qualif
,
839 _
=> ConstQualif
::NOT_CONST
842 // Compute maximum lifetime of this rvalue. This is 'static if
843 // we can promote to a constant, otherwise equal to enclosing temp
845 let re
= if qualif
.intersects(ConstQualif
::NON_STATIC_BORROWS
) {
846 self.temporary_scope(id
)
850 let ret
= self.cat_rvalue(id
, span
, re
, expr_ty
);
851 debug
!("cat_rvalue_node ret {:?}", ret
);
855 pub fn cat_rvalue(&self,
858 temp_scope
: ty
::Region
,
859 expr_ty
: Ty
<'tcx
>) -> cmt
<'tcx
> {
860 let ret
= Rc
::new(cmt_
{
863 cat
:Categorization
::Rvalue(temp_scope
),
868 debug
!("cat_rvalue ret {:?}", ret
);
872 pub fn cat_field
<N
:ast_node
>(&self,
878 let ret
= Rc
::new(cmt_
{
881 mutbl
: base_cmt
.mutbl
.inherit(),
882 cat
: Categorization
::Interior(base_cmt
, InteriorField(NamedField(f_name
))),
886 debug
!("cat_field ret {:?}", ret
);
890 pub fn cat_tup_field
<N
:ast_node
>(&self,
896 let ret
= Rc
::new(cmt_
{
899 mutbl
: base_cmt
.mutbl
.inherit(),
900 cat
: Categorization
::Interior(base_cmt
, InteriorField(PositionalField(f_idx
))),
904 debug
!("cat_tup_field ret {:?}", ret
);
908 fn cat_deref
<N
:ast_node
>(&self,
912 deref_context
: DerefKindContext
)
913 -> McResult
<cmt
<'tcx
>> {
914 let method_call
= ty
::MethodCall
{
916 autoderef
: deref_cnt
as u32
918 let method_ty
= self.infcx
.node_method_ty(method_call
);
920 debug
!("cat_deref: method_call={:?} method_ty={:?}",
921 method_call
, method_ty
.map(|ty
| ty
));
923 let base_cmt
= match method_ty
{
926 self.tcx().no_late_bound_regions(&method_ty
.fn_ret()).unwrap();
927 self.cat_rvalue_node(node
.id(), node
.span(), ref_ty
)
931 let base_cmt_ty
= base_cmt
.ty
;
932 match base_cmt_ty
.builtin_deref(true, ty
::NoPreference
) {
934 let ret
= self.cat_deref_common(node
, base_cmt
, deref_cnt
,
937 /* implicit: */ false);
938 debug
!("cat_deref ret {:?}", ret
);
942 debug
!("Explicit deref of non-derefable type: {:?}",
949 fn cat_deref_common
<N
:ast_node
>(&self,
954 deref_context
: DerefKindContext
,
956 -> McResult
<cmt
<'tcx
>>
958 let (m
, cat
) = match deref_kind(base_cmt
.ty
, deref_context
)?
{
960 let ptr
= if implicit
{
962 BorrowedPtr(bk
, r
) => Implicit(bk
, r
),
963 _
=> span_bug
!(node
.span(),
964 "Implicit deref of non-borrowed pointer")
969 // for unique ptrs, we inherit mutability from the
971 (MutabilityCategory
::from_pointer_kind(base_cmt
.mutbl
, ptr
),
972 Categorization
::Deref(base_cmt
, deref_cnt
, ptr
))
974 deref_interior(interior
) => {
975 (base_cmt
.mutbl
.inherit(), Categorization
::Interior(base_cmt
, interior
))
978 let ret
= Rc
::new(cmt_
{
986 debug
!("cat_deref_common ret {:?}", ret
);
990 pub fn cat_index
<N
:ast_node
>(&self,
992 mut base_cmt
: cmt
<'tcx
>,
993 context
: InteriorOffsetKind
)
994 -> McResult
<cmt
<'tcx
>> {
995 //! Creates a cmt for an indexing operation (`[]`).
997 //! One subtle aspect of indexing that may not be
998 //! immediately obvious: for anything other than a fixed-length
999 //! vector, an operation like `x[y]` actually consists of two
1000 //! disjoint (from the point of view of borrowck) operations.
1001 //! The first is a deref of `x` to create a pointer `p` that points
1002 //! at the first element in the array. The second operation is
1003 //! an index which adds `y*sizeof(T)` to `p` to obtain the
1004 //! pointer to `x[y]`. `cat_index` will produce a resulting
1005 //! cmt containing both this deref and the indexing,
1006 //! presuming that `base_cmt` is not of fixed-length type.
1009 //! - `elt`: the AST node being indexed
1010 //! - `base_cmt`: the cmt of `elt`
1012 let method_call
= ty
::MethodCall
::expr(elt
.id());
1013 let method_ty
= self.infcx
.node_method_ty(method_call
);
1015 let (element_ty
, element_kind
) = match method_ty
{
1016 Some(method_ty
) => {
1017 let ref_ty
= self.overloaded_method_return_ty(method_ty
);
1018 base_cmt
= self.cat_rvalue_node(elt
.id(), elt
.span(), ref_ty
);
1020 // FIXME(#20649) -- why are we using the `self_ty` as the element type...?
1021 let self_ty
= method_ty
.fn_sig().input(0);
1022 (self.tcx().no_late_bound_regions(&self_ty
).unwrap(),
1023 ElementKind
::OtherElement
)
1026 match base_cmt
.ty
.builtin_index() {
1027 Some(ty
) => (ty
, ElementKind
::VecElement
),
1035 let interior_elem
= InteriorElement(context
, element_kind
);
1037 self.cat_imm_interior(elt
, base_cmt
.clone(), element_ty
, interior_elem
);
1038 debug
!("cat_index ret {:?}", ret
);
1042 pub fn cat_imm_interior
<N
:ast_node
>(&self,
1044 base_cmt
: cmt
<'tcx
>,
1045 interior_ty
: Ty
<'tcx
>,
1046 interior
: InteriorKind
)
1048 let ret
= Rc
::new(cmt_
{
1051 mutbl
: base_cmt
.mutbl
.inherit(),
1052 cat
: Categorization
::Interior(base_cmt
, interior
),
1056 debug
!("cat_imm_interior ret={:?}", ret
);
1060 pub fn cat_downcast
<N
:ast_node
>(&self,
1062 base_cmt
: cmt
<'tcx
>,
1063 downcast_ty
: Ty
<'tcx
>,
1066 let ret
= Rc
::new(cmt_
{
1069 mutbl
: base_cmt
.mutbl
.inherit(),
1070 cat
: Categorization
::Downcast(base_cmt
, variant_did
),
1074 debug
!("cat_downcast ret={:?}", ret
);
1078 pub fn cat_pattern
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &hir
::Pat
, mut op
: F
) -> McResult
<()>
1079 where F
: FnMut(&MemCategorizationContext
<'a
, 'gcx
, 'tcx
>, cmt
<'tcx
>, &hir
::Pat
),
1081 self.cat_pattern_(cmt
, pat
, &mut op
)
1084 // FIXME(#19596) This is a workaround, but there should be a better way to do this
1085 fn cat_pattern_
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &hir
::Pat
, op
: &mut F
) -> McResult
<()>
1086 where F
: FnMut(&MemCategorizationContext
<'a
, 'gcx
, 'tcx
>, cmt
<'tcx
>, &hir
::Pat
)
1088 // Here, `cmt` is the categorization for the value being
1089 // matched and pat is the pattern it is being matched against.
1091 // In general, the way that this works is that we walk down
1092 // the pattern, constructing a cmt that represents the path
1093 // that will be taken to reach the value being matched.
1095 // When we encounter named bindings, we take the cmt that has
1096 // been built up and pass it off to guarantee_valid() so that
1097 // we can be sure that the binding will remain valid for the
1098 // duration of the arm.
1100 // (*2) There is subtlety concerning the correspondence between
1101 // pattern ids and types as compared to *expression* ids and
1102 // types. This is explained briefly. on the definition of the
1103 // type `cmt`, so go off and read what it says there, then
1104 // come back and I'll dive into a bit more detail here. :) OK,
1107 // In general, the id of the cmt should be the node that
1108 // "produces" the value---patterns aren't executable code
1109 // exactly, but I consider them to "execute" when they match a
1110 // value, and I consider them to produce the value that was
1111 // matched. So if you have something like:
1118 // In this case, the cmt and the relevant ids would be:
1120 // CMT Id Type of Id Type of cmt
1123 // ^~~~~~~^ `x` from discr @@int @@int
1124 // ^~~~~~~~~~^ `@@y` pattern node @@int @int
1125 // ^~~~~~~~~~~~~^ `@y` pattern node @int int
1127 // You can see that the types of the id and the cmt are in
1128 // sync in the first line, because that id is actually the id
1129 // of an expression. But once we get to pattern ids, the types
1130 // step out of sync again. So you'll see below that we always
1131 // get the type of the *subpattern* and use that.
1133 debug
!("cat_pattern: {:?} cmt={:?}", pat
, cmt
);
1135 op(self, cmt
.clone(), pat
);
1137 // Note: This goes up here (rather than within the PatKind::TupleStruct arm
1138 // alone) because PatKind::Struct can also refer to variants.
1139 let cmt
= match self.tcx().expect_def_or_none(pat
.id
) {
1140 Some(Def
::Err
) => return Err(()),
1141 Some(Def
::Variant(enum_did
, variant_did
))
1142 // univariant enums do not need downcasts
1143 if !self.tcx().lookup_adt_def(enum_did
).is_univariant() => {
1144 self.cat_downcast(pat
, cmt
.clone(), cmt
.ty
, variant_did
)
1150 PatKind
::TupleStruct(_
, ref subpats
, ddpos
) => {
1151 let expected_len
= match self.tcx().expect_def(pat
.id
) {
1152 Def
::Variant(enum_def
, def_id
) => {
1153 self.tcx().lookup_adt_def(enum_def
).variant_with_id(def_id
).fields
.len()
1155 Def
::Struct(..) => {
1156 match self.pat_ty(&pat
)?
.sty
{
1157 ty
::TyStruct(adt_def
, _
) => {
1158 adt_def
.struct_variant().fields
.len()
1161 span_bug
!(pat
.span
, "tuple struct pattern unexpected type {:?}", ty
);
1166 span_bug
!(pat
.span
, "tuple struct pattern didn't resolve \
1167 to variant or struct {:?}", def
);
1171 for (i
, subpat
) in subpats
.iter().enumerate_and_adjust(expected_len
, ddpos
) {
1172 let subpat_ty
= self.pat_ty(&subpat
)?
; // see (*2)
1173 let subcmt
= self.cat_imm_interior(pat
, cmt
.clone(), subpat_ty
,
1174 InteriorField(PositionalField(i
)));
1175 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1179 PatKind
::Struct(_
, ref field_pats
, _
) => {
1180 // {f1: p1, ..., fN: pN}
1181 for fp
in field_pats
{
1182 let field_ty
= self.pat_ty(&fp
.node
.pat
)?
; // see (*2)
1183 let cmt_field
= self.cat_field(pat
, cmt
.clone(), fp
.node
.name
, field_ty
);
1184 self.cat_pattern_(cmt_field
, &fp
.node
.pat
, op
)?
;
1188 PatKind
::Binding(_
, _
, Some(ref subpat
)) => {
1189 self.cat_pattern_(cmt
, &subpat
, op
)?
;
1192 PatKind
::Tuple(ref subpats
, ddpos
) => {
1194 let expected_len
= match self.pat_ty(&pat
)?
.sty
{
1195 ty
::TyTuple(ref tys
) => tys
.len(),
1196 ref ty
=> span_bug
!(pat
.span
, "tuple pattern unexpected type {:?}", ty
),
1198 for (i
, subpat
) in subpats
.iter().enumerate_and_adjust(expected_len
, ddpos
) {
1199 let subpat_ty
= self.pat_ty(&subpat
)?
; // see (*2)
1200 let subcmt
= self.cat_imm_interior(pat
, cmt
.clone(), subpat_ty
,
1201 InteriorField(PositionalField(i
)));
1202 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1206 PatKind
::Box(ref subpat
) | PatKind
::Ref(ref subpat
, _
) => {
1207 // box p1, &p1, &mut p1. we can ignore the mutability of
1208 // PatKind::Ref since that information is already contained
1210 let subcmt
= self.cat_deref(pat
, cmt
, 0, None
)?
;
1211 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1214 PatKind
::Vec(ref before
, ref slice
, ref after
) => {
1215 let context
= InteriorOffsetKind
::Pattern
;
1216 let elt_cmt
= self.cat_index(pat
, cmt
, context
)?
;
1217 for before_pat
in before
{
1218 self.cat_pattern_(elt_cmt
.clone(), &before_pat
, op
)?
;
1220 if let Some(ref slice_pat
) = *slice
{
1221 self.cat_pattern_(elt_cmt
.clone(), &slice_pat
, op
)?
;
1223 for after_pat
in after
{
1224 self.cat_pattern_(elt_cmt
.clone(), &after_pat
, op
)?
;
1228 PatKind
::Path(..) | PatKind
::Binding(_
, _
, None
) |
1229 PatKind
::Lit(..) | PatKind
::Range(..) | PatKind
::Wild
=> {
1237 fn overloaded_method_return_ty(&self,
1238 method_ty
: Ty
<'tcx
>)
1241 // When we process an overloaded `*` or `[]` etc, we often
1242 // need to extract the return type of the method. These method
1243 // types are generated by method resolution and always have
1244 // all late-bound regions fully instantiated, so we just want
1245 // to skip past the binder.
1246 self.tcx().no_late_bound_regions(&method_ty
.fn_ret())
1251 #[derive(Clone, Debug)]
1252 pub enum Aliasability
{
1253 FreelyAliasable(AliasableReason
),
1255 ImmutableUnique(Box
<Aliasability
>),
1258 #[derive(Copy, Clone, Debug)]
1259 pub enum AliasableReason
{
1261 AliasableClosure(ast
::NodeId
), // Aliasable due to capture Fn closure env
1263 UnaliasableImmutable
, // Created as needed upon seeing ImmutableUnique
1268 impl<'tcx
> cmt_
<'tcx
> {
1269 pub fn guarantor(&self) -> cmt
<'tcx
> {
1270 //! Returns `self` after stripping away any derefs or
1271 //! interior content. The return value is basically the `cmt` which
1272 //! determines how long the value in `self` remains live.
1275 Categorization
::Rvalue(..) |
1276 Categorization
::StaticItem
|
1277 Categorization
::Local(..) |
1278 Categorization
::Deref(_
, _
, UnsafePtr(..)) |
1279 Categorization
::Deref(_
, _
, BorrowedPtr(..)) |
1280 Categorization
::Deref(_
, _
, Implicit(..)) |
1281 Categorization
::Upvar(..) => {
1282 Rc
::new((*self).clone())
1284 Categorization
::Downcast(ref b
, _
) |
1285 Categorization
::Interior(ref b
, _
) |
1286 Categorization
::Deref(ref b
, _
, Unique
) => {
1292 /// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
1293 pub fn freely_aliasable(&self) -> Aliasability
{
1294 // Maybe non-obvious: copied upvars can only be considered
1295 // non-aliasable in once closures, since any other kind can be
1296 // aliased and eventually recused.
1299 Categorization
::Deref(ref b
, _
, BorrowedPtr(ty
::MutBorrow
, _
)) |
1300 Categorization
::Deref(ref b
, _
, Implicit(ty
::MutBorrow
, _
)) |
1301 Categorization
::Deref(ref b
, _
, BorrowedPtr(ty
::UniqueImmBorrow
, _
)) |
1302 Categorization
::Deref(ref b
, _
, Implicit(ty
::UniqueImmBorrow
, _
)) |
1303 Categorization
::Downcast(ref b
, _
) |
1304 Categorization
::Interior(ref b
, _
) => {
1305 // Aliasability depends on base cmt
1306 b
.freely_aliasable()
1309 Categorization
::Deref(ref b
, _
, Unique
) => {
1310 let sub
= b
.freely_aliasable();
1311 if b
.mutbl
.is_mutable() {
1312 // Aliasability depends on base cmt alone
1315 // Do not allow mutation through an immutable box.
1316 ImmutableUnique(Box
::new(sub
))
1320 Categorization
::Rvalue(..) |
1321 Categorization
::Local(..) |
1322 Categorization
::Upvar(..) |
1323 Categorization
::Deref(_
, _
, UnsafePtr(..)) => { // yes, it's aliasable, but...
1327 Categorization
::StaticItem
=> {
1328 if self.mutbl
.is_mutable() {
1329 FreelyAliasable(AliasableStaticMut
)
1331 FreelyAliasable(AliasableStatic
)
1335 Categorization
::Deref(ref base
, _
, BorrowedPtr(ty
::ImmBorrow
, _
)) |
1336 Categorization
::Deref(ref base
, _
, Implicit(ty
::ImmBorrow
, _
)) => {
1338 Categorization
::Upvar(Upvar{ id, .. }
) =>
1339 FreelyAliasable(AliasableClosure(id
.closure_expr_id
)),
1340 _
=> FreelyAliasable(AliasableBorrowed
)
1346 // Digs down through one or two layers of deref and grabs the cmt
1347 // for the upvar if a note indicates there is one.
1348 pub fn upvar(&self) -> Option
<cmt
<'tcx
>> {
1350 NoteClosureEnv(..) | NoteUpvarRef(..) => {
1351 Some(match self.cat
{
1352 Categorization
::Deref(ref inner
, _
, _
) => {
1354 Categorization
::Deref(ref inner
, _
, _
) => inner
.clone(),
1355 Categorization
::Upvar(..) => inner
.clone(),
1367 pub fn descriptive_string(&self, tcx
: TyCtxt
) -> String
{
1369 Categorization
::StaticItem
=> {
1370 "static item".to_string()
1372 Categorization
::Rvalue(..) => {
1373 "non-lvalue".to_string()
1375 Categorization
::Local(vid
) => {
1376 if tcx
.map
.is_argument(vid
) {
1377 "argument".to_string()
1379 "local variable".to_string()
1382 Categorization
::Deref(_
, _
, pk
) => {
1383 let upvar
= self.upvar();
1384 match upvar
.as_ref().map(|i
| &i
.cat
) {
1385 Some(&Categorization
::Upvar(ref var
)) => {
1392 format
!("indexed content")
1395 format
!("`Box` content")
1398 format
!("dereference of raw pointer")
1400 BorrowedPtr(..) => {
1401 format
!("borrowed content")
1407 Categorization
::Interior(_
, InteriorField(NamedField(_
))) => {
1410 Categorization
::Interior(_
, InteriorField(PositionalField(_
))) => {
1411 "anonymous field".to_string()
1413 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1415 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1417 "indexed content".to_string()
1419 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1421 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1423 "pattern-bound indexed content".to_string()
1425 Categorization
::Upvar(ref var
) => {
1428 Categorization
::Downcast(ref cmt
, _
) => {
1429 cmt
.descriptive_string(tcx
)
1435 impl<'tcx
> fmt
::Debug
for cmt_
<'tcx
> {
1436 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1437 write
!(f
, "{{{:?} id:{} m:{:?} ty:{:?}}}",
1445 impl<'tcx
> fmt
::Debug
for Categorization
<'tcx
> {
1446 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1448 Categorization
::StaticItem
=> write
!(f
, "static"),
1449 Categorization
::Rvalue(r
) => write
!(f
, "rvalue({:?})", r
),
1450 Categorization
::Local(id
) => {
1451 let name
= ty
::tls
::with(|tcx
| tcx
.local_var_name_str(id
));
1452 write
!(f
, "local({})", name
)
1454 Categorization
::Upvar(upvar
) => {
1455 write
!(f
, "upvar({:?})", upvar
)
1457 Categorization
::Deref(ref cmt
, derefs
, ptr
) => {
1458 write
!(f
, "{:?}-{:?}{}->", cmt
.cat
, ptr
, derefs
)
1460 Categorization
::Interior(ref cmt
, interior
) => {
1461 write
!(f
, "{:?}.{:?}", cmt
.cat
, interior
)
1463 Categorization
::Downcast(ref cmt
, _
) => {
1464 write
!(f
, "{:?}->(enum)", cmt
.cat
)
1470 pub fn ptr_sigil(ptr
: PointerKind
) -> &'
static str {
1473 BorrowedPtr(ty
::ImmBorrow
, _
) |
1474 Implicit(ty
::ImmBorrow
, _
) => "&",
1475 BorrowedPtr(ty
::MutBorrow
, _
) |
1476 Implicit(ty
::MutBorrow
, _
) => "&mut",
1477 BorrowedPtr(ty
::UniqueImmBorrow
, _
) |
1478 Implicit(ty
::UniqueImmBorrow
, _
) => "&unique",
1479 UnsafePtr(_
) => "*",
1483 impl fmt
::Debug
for PointerKind
{
1484 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1486 Unique
=> write
!(f
, "Box"),
1487 BorrowedPtr(ty
::ImmBorrow
, ref r
) |
1488 Implicit(ty
::ImmBorrow
, ref r
) => {
1489 write
!(f
, "&{:?}", r
)
1491 BorrowedPtr(ty
::MutBorrow
, ref r
) |
1492 Implicit(ty
::MutBorrow
, ref r
) => {
1493 write
!(f
, "&{:?} mut", r
)
1495 BorrowedPtr(ty
::UniqueImmBorrow
, ref r
) |
1496 Implicit(ty
::UniqueImmBorrow
, ref r
) => {
1497 write
!(f
, "&{:?} uniq", r
)
1499 UnsafePtr(_
) => write
!(f
, "*")
1504 impl fmt
::Debug
for InteriorKind
{
1505 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1507 InteriorField(NamedField(fld
)) => write
!(f
, "{}", fld
),
1508 InteriorField(PositionalField(i
)) => write
!(f
, "#{}", i
),
1509 InteriorElement(..) => write
!(f
, "[]"),
1514 impl fmt
::Debug
for Upvar
{
1515 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1516 write
!(f
, "{:?}/{:?}", self.id
, self.kind
)
1520 impl fmt
::Display
for Upvar
{
1521 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1522 let kind
= match self.kind
{
1523 ty
::ClosureKind
::Fn
=> "Fn",
1524 ty
::ClosureKind
::FnMut
=> "FnMut",
1525 ty
::ClosureKind
::FnOnce
=> "FnOnce",
1527 write
!(f
, "captured outer variable in an `{}` closure", kind
)