3 //! The job of the categorization module is to analyze an expression to
4 //! determine what kind of memory is used in evaluating it (for example,
5 //! where dereferences occur and what kind of pointer is dereferenced;
6 //! whether the memory is mutable, etc.).
8 //! Categorization effectively transforms all of our expressions into
9 //! expressions of the following forms (the actual enum has many more
10 //! possibilities, naturally, but they are all variants of these base
13 //! E = rvalue // some computed rvalue
14 //! | x // address of a local variable or argument
15 //! | *E // deref of a ptr
16 //! | E.comp // access to an interior component
18 //! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
19 //! address where the result is to be found. If Expr is a place, then this
20 //! is the address of the place. If `Expr` is an rvalue, this is the address of
21 //! some temporary spot in memory where the result is stored.
23 //! Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
26 //! - `cat`: what kind of expression was this? This is a subset of the
27 //! full expression forms which only includes those that we care about
28 //! for the purpose of the analysis.
29 //! - `mutbl`: mutability of the address `A`.
30 //! - `ty`: the type of data found at the address `A`.
32 //! The resulting categorization tree differs somewhat from the expressions
33 //! themselves. For example, auto-derefs are explicit. Also, an index a[b] is
34 //! decomposed into two operations: a dereference to reach the array data and
35 //! then an index to jump forward to the relevant item.
37 //! ## By-reference upvars
39 //! One part of the codegen which may be non-obvious is that we translate
40 //! closure upvars into the dereference of a borrowed pointer; this more closely
41 //! resembles the runtime codegen. So, for example, if we had:
45 //! let inc = || x += y;
47 //! Then when we categorize `x` (*within* the closure) we would yield a
48 //! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
49 //! tied to `x`. The type of `x'` will be a borrowed pointer.
51 #![allow(non_camel_case_types)]
53 pub use self::PointerKind
::*;
54 pub use self::InteriorKind
::*;
55 pub use self::MutabilityCategory
::*;
56 pub use self::AliasableReason
::*;
57 pub use self::Note
::*;
59 use self::Aliasability
::*;
61 use crate::middle
::region
;
62 use crate::hir
::def_id
::{DefId, LocalDefId}
;
64 use crate::infer
::InferCtxt
;
65 use crate::hir
::def
::{CtorOf, Res, DefKind, CtorKind}
;
66 use crate::ty
::adjustment
;
67 use crate::ty
::{self, DefIdTree, Ty, TyCtxt}
;
68 use crate::ty
::fold
::TypeFoldable
;
70 use crate::hir
::{MutImmutable, MutMutable, PatKind}
;
71 use crate::hir
::pat_util
::EnumerateAndAdjustIterator
;
73 use syntax
::ast
::{self, Name}
;
74 use syntax
::symbol
::sym
;
79 use std
::hash
::{Hash, Hasher}
;
80 use rustc_data_structures
::fx
::FxIndexMap
;
83 #[derive(Clone, Debug, PartialEq)]
84 pub enum Categorization
<'tcx
> {
85 Rvalue
, // temporary val
86 ThreadLocal
, // value that cannot move, but still restricted in scope
88 Upvar(Upvar
), // upvar referenced by closure env
89 Local(hir
::HirId
), // local variable
90 Deref(cmt
<'tcx
>, PointerKind
<'tcx
>), // deref of a ptr
91 Interior(cmt
<'tcx
>, InteriorKind
), // something interior: field, tuple, etc
92 Downcast(cmt
<'tcx
>, DefId
), // selects a particular enum variant (*1)
94 // (*1) downcast is only required if the enum has more than one variant
97 // Represents any kind of upvar
98 #[derive(Clone, Copy, PartialEq)]
101 pub kind
: ty
::ClosureKind
104 // different kinds of pointers:
105 #[derive(Clone, Copy, Debug, PartialEq)]
106 pub enum PointerKind
<'tcx
> {
111 BorrowedPtr(ty
::BorrowKind
, ty
::Region
<'tcx
>),
114 UnsafePtr(hir
::Mutability
),
117 // We use the term "interior" to mean "something reachable from the
118 // base without a pointer dereference", e.g., a field
119 #[derive(Clone, PartialEq)]
120 pub enum InteriorKind
{
121 InteriorField(FieldIndex
),
122 InteriorElement(InteriorOffsetKind
),
125 // Contains index of a field that is actually used for loan path comparisons and
126 // string representation of the field that should be used only for diagnostics.
127 #[derive(Clone, Copy, Eq)]
128 pub struct FieldIndex(pub usize, pub Name
);
130 impl PartialEq
for FieldIndex
{
131 fn eq(&self, rhs
: &Self) -> bool
{
136 impl Hash
for FieldIndex
{
137 fn hash
<H
: Hasher
>(&self, h
: &mut H
) {
142 #[derive(Clone, PartialEq)]
143 pub enum InteriorOffsetKind
{
144 Index
, // e.g., `array_expr[index_expr]`
145 Pattern
, // e.g., `fn foo([_, a, _, _]: [A; 4]) { ... }`
148 #[derive(Clone, Copy, PartialEq, Debug)]
149 pub enum MutabilityCategory
{
150 McImmutable
, // Immutable.
151 McDeclared
, // Directly declared as mutable.
152 McInherited
, // Inherited from the fact that owner is mutable.
155 // A note about the provenance of a `cmt`. This is used for
156 // special-case handling of upvars such as mutability inference.
157 // Upvar categorization can generate a variable number of nested
158 // derefs. The note allows detecting them without deep pattern
159 // matching on the categorization.
160 #[derive(Clone, Copy, PartialEq, Debug)]
162 NoteClosureEnv(ty
::UpvarId
), // Deref through closure env
163 NoteUpvarRef(ty
::UpvarId
), // Deref through by-ref upvar
164 NoteIndex
, // Deref as part of desugaring `x[]` into its two components
165 NoteNone
// Nothing special
168 // `cmt`: "Category, Mutability, and Type".
170 // a complete categorization of a value indicating where it originated
171 // and how it is located, as well as the mutability of the memory in
172 // which the value is stored.
174 // *WARNING* The field `cmt.type` is NOT necessarily the same as the
175 // result of `node_type(cmt.id)`.
177 // (FIXME: rewrite the following comment given that `@x` managed
178 // pointers have been obsolete for quite some time.)
180 // This is because the `id` is always the `id` of the node producing the
181 // type; in an expression like `*x`, the type of this deref node is the
182 // deref'd type (`T`), but in a pattern like `@x`, the `@x` pattern is
183 // again a dereference, but its type is the type *before* the
184 // dereference (`@T`). So use `cmt.ty` to find the type of the value in
185 // a consistent fashion. For more details, see the method `cat_pattern`
186 #[derive(Clone, Debug, PartialEq)]
187 pub struct cmt_
<'tcx
> {
188 pub hir_id
: hir
::HirId
, // HIR 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 place
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
>>;
199 fn hir_id(&self) -> hir
::HirId
;
200 fn span(&self) -> Span
;
203 impl HirNode
for hir
::Expr
{
204 fn hir_id(&self) -> hir
::HirId { self.hir_id }
205 fn span(&self) -> Span { self.span }
208 impl HirNode
for hir
::Pat
{
209 fn hir_id(&self) -> hir
::HirId { self.hir_id }
210 fn span(&self) -> Span { self.span }
214 pub struct MemCategorizationContext
<'a
, 'tcx
> {
215 pub tcx
: TyCtxt
<'tcx
>,
216 param_env
: ty
::ParamEnv
<'tcx
>,
217 pub body_owner
: DefId
,
218 pub upvars
: Option
<&'tcx FxIndexMap
<hir
::HirId
, hir
::Upvar
>>,
219 pub region_scope_tree
: &'a region
::ScopeTree
,
220 pub tables
: &'a ty
::TypeckTables
<'tcx
>,
221 infcx
: Option
<&'a InferCtxt
<'a
, 'tcx
>>,
224 pub type McResult
<T
> = Result
<T
, ()>;
226 impl MutabilityCategory
{
227 pub fn from_mutbl(m
: hir
::Mutability
) -> MutabilityCategory
{
229 MutImmutable
=> McImmutable
,
230 MutMutable
=> McDeclared
232 debug
!("MutabilityCategory::{}({:?}) => {:?}",
233 "from_mutbl", m
, ret
);
237 pub fn from_borrow_kind(borrow_kind
: ty
::BorrowKind
) -> MutabilityCategory
{
238 let ret
= match borrow_kind
{
239 ty
::ImmBorrow
=> McImmutable
,
240 ty
::UniqueImmBorrow
=> McImmutable
,
241 ty
::MutBorrow
=> McDeclared
,
243 debug
!("MutabilityCategory::{}({:?}) => {:?}",
244 "from_borrow_kind", borrow_kind
, ret
);
248 fn from_pointer_kind(base_mutbl
: MutabilityCategory
,
249 ptr
: PointerKind
<'_
>) -> MutabilityCategory
{
250 let ret
= match ptr
{
254 BorrowedPtr(borrow_kind
, _
) => {
255 MutabilityCategory
::from_borrow_kind(borrow_kind
)
258 MutabilityCategory
::from_mutbl(m
)
261 debug
!("MutabilityCategory::{}({:?}, {:?}) => {:?}",
262 "from_pointer_kind", base_mutbl
, ptr
, ret
);
268 tables
: &ty
::TypeckTables
<'_
>,
270 ) -> MutabilityCategory
{
271 let ret
= match tcx
.hir().get(id
) {
272 Node
::Binding(p
) => match p
.kind
{
273 PatKind
::Binding(..) => {
274 let bm
= *tables
.pat_binding_modes()
276 .expect("missing binding mode");
277 if bm
== ty
::BindByValue(hir
::MutMutable
) {
283 _
=> span_bug
!(p
.span
, "expected identifier pattern")
285 _
=> span_bug
!(tcx
.hir().span(id
), "expected identifier pattern")
287 debug
!("MutabilityCategory::{}(tcx, id={:?}) => {:?}",
288 "from_local", id
, ret
);
292 pub fn inherit(&self) -> MutabilityCategory
{
293 let ret
= match *self {
294 McImmutable
=> McImmutable
,
295 McDeclared
=> McInherited
,
296 McInherited
=> McInherited
,
298 debug
!("{:?}.inherit() => {:?}", self, ret
);
302 pub fn is_mutable(&self) -> bool
{
303 let ret
= match *self {
304 McImmutable
=> false,
308 debug
!("{:?}.is_mutable() => {:?}", self, ret
);
312 pub fn is_immutable(&self) -> bool
{
313 let ret
= match *self {
315 McDeclared
| McInherited
=> false
317 debug
!("{:?}.is_immutable() => {:?}", self, ret
);
321 pub fn to_user_str(&self) -> &'
static str {
323 McDeclared
| McInherited
=> "mutable",
324 McImmutable
=> "immutable",
329 impl<'a
, 'tcx
> MemCategorizationContext
<'a
, 'tcx
> {
332 param_env
: ty
::ParamEnv
<'tcx
>,
334 region_scope_tree
: &'a region
::ScopeTree
,
335 tables
: &'a ty
::TypeckTables
<'tcx
>,
336 ) -> MemCategorizationContext
<'a
, 'tcx
> {
337 MemCategorizationContext
{
340 upvars
: tcx
.upvars(body_owner
),
349 impl<'a
, 'tcx
> MemCategorizationContext
<'a
, 'tcx
> {
350 /// Creates a `MemCategorizationContext` during type inference.
351 /// This is used during upvar analysis and a few other places.
352 /// Because the typeck tables are not yet complete, the results
353 /// from the analysis must be used with caution:
355 /// - rvalue promotions are not known, so the lifetimes of
356 /// temporaries may be overly conservative;
357 /// - similarly, as the results of upvar analysis are not yet
358 /// known, the results around upvar accesses may be incorrect.
360 infcx
: &'a InferCtxt
<'a
, 'tcx
>,
361 param_env
: ty
::ParamEnv
<'tcx
>,
363 region_scope_tree
: &'a region
::ScopeTree
,
364 tables
: &'a ty
::TypeckTables
<'tcx
>,
365 ) -> MemCategorizationContext
<'a
, 'tcx
> {
368 MemCategorizationContext
{
371 upvars
: tcx
.upvars(body_owner
),
379 pub fn type_is_copy_modulo_regions(
381 param_env
: ty
::ParamEnv
<'tcx
>,
385 self.infcx
.map(|infcx
| infcx
.type_is_copy_modulo_regions(param_env
, ty
, span
))
387 if (param_env
, ty
).has_local_value() {
390 Some(ty
.is_copy_modulo_regions(self.tcx
, param_env
, span
))
396 fn resolve_vars_if_possible
<T
>(&self, value
: &T
) -> T
397 where T
: TypeFoldable
<'tcx
>
399 self.infcx
.map(|infcx
| infcx
.resolve_vars_if_possible(value
))
400 .unwrap_or_else(|| value
.clone())
403 fn is_tainted_by_errors(&self) -> bool
{
404 self.infcx
.map_or(false, |infcx
| infcx
.is_tainted_by_errors())
407 fn resolve_type_vars_or_error(&self,
409 ty
: Option
<Ty
<'tcx
>>)
410 -> McResult
<Ty
<'tcx
>> {
413 let ty
= self.resolve_vars_if_possible(&ty
);
414 if ty
.references_error() || ty
.is_ty_var() {
415 debug
!("resolve_type_vars_or_error: error from {:?}", ty
);
422 None
if self.is_tainted_by_errors() => Err(()),
424 bug
!("no type for node {}: {} in mem_categorization",
425 id
, self.tcx
.hir().node_to_string(id
));
430 pub fn node_ty(&self,
432 -> McResult
<Ty
<'tcx
>> {
433 self.resolve_type_vars_or_error(hir_id
,
434 self.tables
.node_type_opt(hir_id
))
437 pub fn expr_ty(&self, expr
: &hir
::Expr
) -> McResult
<Ty
<'tcx
>> {
438 self.resolve_type_vars_or_error(expr
.hir_id
, self.tables
.expr_ty_opt(expr
))
441 pub fn expr_ty_adjusted(&self, expr
: &hir
::Expr
) -> McResult
<Ty
<'tcx
>> {
442 self.resolve_type_vars_or_error(expr
.hir_id
, self.tables
.expr_ty_adjusted_opt(expr
))
445 /// Returns the type of value that this pattern matches against.
446 /// Some non-obvious cases:
448 /// - a `ref x` binding matches against a value of type `T` and gives
449 /// `x` the type `&T`; we return `T`.
450 /// - a pattern with implicit derefs (thanks to default binding
451 /// modes #42640) may look like `Some(x)` but in fact have
452 /// implicit deref patterns attached (e.g., it is really
453 /// `&Some(x)`). In that case, we return the "outermost" type
454 /// (e.g., `&Option<T>).
455 pub fn pat_ty_adjusted(&self, pat
: &hir
::Pat
) -> McResult
<Ty
<'tcx
>> {
456 // Check for implicit `&` types wrapping the pattern; note
457 // that these are never attached to binding patterns, so
458 // actually this is somewhat "disjoint" from the code below
459 // that aims to account for `ref x`.
460 if let Some(vec
) = self.tables
.pat_adjustments().get(pat
.hir_id
) {
461 if let Some(first_ty
) = vec
.first() {
462 debug
!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat
, first_ty
);
467 self.pat_ty_unadjusted(pat
)
471 /// Like `pat_ty`, but ignores implicit `&` patterns.
472 fn pat_ty_unadjusted(&self, pat
: &hir
::Pat
) -> McResult
<Ty
<'tcx
>> {
473 let base_ty
= self.node_ty(pat
.hir_id
)?
;
474 debug
!("pat_ty(pat={:?}) base_ty={:?}", pat
, base_ty
);
476 // This code detects whether we are looking at a `ref x`,
477 // and if so, figures out what the type *being borrowed* is.
478 let ret_ty
= match pat
.kind
{
479 PatKind
::Binding(..) => {
480 let bm
= *self.tables
483 .expect("missing binding mode");
485 if let ty
::BindByReference(_
) = bm
{
486 // a bind-by-ref means that the base_ty will be the type of the ident itself,
487 // but what we want here is the type of the underlying value being borrowed.
488 // So peel off one-level, turning the &T into T.
489 match base_ty
.builtin_deref(false) {
492 debug
!("By-ref binding of non-derefable type {:?}", base_ty
);
502 debug
!("pat_ty(pat={:?}) ret_ty={:?}", pat
, ret_ty
);
507 pub fn cat_expr(&self, expr
: &hir
::Expr
) -> McResult
<cmt_
<'tcx
>> {
508 // This recursion helper avoids going through *too many*
509 // adjustments, since *only* non-overloaded deref recurses.
511 mc
: &MemCategorizationContext
<'a
, 'tcx
>,
513 adjustments
: &[adjustment
::Adjustment
<'tcx
>],
514 ) -> McResult
<cmt_
<'tcx
>> {
515 match adjustments
.split_last() {
516 None
=> mc
.cat_expr_unadjusted(expr
),
517 Some((adjustment
, previous
)) => {
518 mc
.cat_expr_adjusted_with(expr
, || helper(mc
, expr
, previous
), adjustment
)
523 helper(self, expr
, self.tables
.expr_adjustments(expr
))
526 pub fn cat_expr_adjusted(&self, expr
: &hir
::Expr
,
527 previous
: cmt_
<'tcx
>,
528 adjustment
: &adjustment
::Adjustment
<'tcx
>)
529 -> McResult
<cmt_
<'tcx
>> {
530 self.cat_expr_adjusted_with(expr
, || Ok(previous
), adjustment
)
533 fn cat_expr_adjusted_with
<F
>(&self, expr
: &hir
::Expr
,
535 adjustment
: &adjustment
::Adjustment
<'tcx
>)
536 -> McResult
<cmt_
<'tcx
>>
537 where F
: FnOnce() -> McResult
<cmt_
<'tcx
>>
539 debug
!("cat_expr_adjusted_with({:?}): {:?}", adjustment
, expr
);
540 let target
= self.resolve_vars_if_possible(&adjustment
.target
);
541 match adjustment
.kind
{
542 adjustment
::Adjust
::Deref(overloaded
) => {
543 // Equivalent to *expr or something similar.
544 let base
= Rc
::new(if let Some(deref
) = overloaded
{
545 let ref_ty
= self.tcx
.mk_ref(deref
.region
, ty
::TypeAndMut
{
549 self.cat_rvalue_node(expr
.hir_id
, expr
.span
, ref_ty
)
553 self.cat_deref(expr
, base
, NoteNone
)
556 adjustment
::Adjust
::NeverToAny
|
557 adjustment
::Adjust
::Pointer(_
) |
558 adjustment
::Adjust
::Borrow(_
) => {
559 // Result is an rvalue.
560 Ok(self.cat_rvalue_node(expr
.hir_id
, expr
.span
, target
))
565 pub fn cat_expr_unadjusted(&self, expr
: &hir
::Expr
) -> McResult
<cmt_
<'tcx
>> {
566 debug
!("cat_expr: id={} expr={:?}", expr
.hir_id
, expr
);
568 let expr_ty
= self.expr_ty(expr
)?
;
570 hir
::ExprKind
::Unary(hir
::UnDeref
, ref e_base
) => {
571 if self.tables
.is_method_call(expr
) {
572 self.cat_overloaded_place(expr
, e_base
, NoteNone
)
574 let base_cmt
= Rc
::new(self.cat_expr(&e_base
)?
);
575 self.cat_deref(expr
, base_cmt
, NoteNone
)
579 hir
::ExprKind
::Field(ref base
, f_ident
) => {
580 let base_cmt
= Rc
::new(self.cat_expr(&base
)?
);
581 debug
!("cat_expr(cat_field): id={} expr={:?} base={:?}",
585 let f_index
= self.tcx
.field_index(expr
.hir_id
, self.tables
);
586 Ok(self.cat_field(expr
, base_cmt
, f_index
, f_ident
, expr_ty
))
589 hir
::ExprKind
::Index(ref base
, _
) => {
590 if self.tables
.is_method_call(expr
) {
591 // If this is an index implemented by a method call, then it
592 // will include an implicit deref of the result.
593 // The call to index() returns a `&T` value, which
594 // is an rvalue. That is what we will be
596 self.cat_overloaded_place(expr
, base
, NoteIndex
)
598 let base_cmt
= Rc
::new(self.cat_expr(&base
)?
);
599 self.cat_index(expr
, base_cmt
, expr_ty
, InteriorOffsetKind
::Index
)
603 hir
::ExprKind
::Path(ref qpath
) => {
604 let res
= self.tables
.qpath_res(qpath
, expr
.hir_id
);
605 self.cat_res(expr
.hir_id
, expr
.span
, expr_ty
, res
)
608 hir
::ExprKind
::Type(ref e
, _
) => {
612 hir
::ExprKind
::AddrOf(..) | hir
::ExprKind
::Call(..) |
613 hir
::ExprKind
::Assign(..) | hir
::ExprKind
::AssignOp(..) |
614 hir
::ExprKind
::Closure(..) | hir
::ExprKind
::Ret(..) |
615 hir
::ExprKind
::Unary(..) | hir
::ExprKind
::Yield(..) |
616 hir
::ExprKind
::MethodCall(..) | hir
::ExprKind
::Cast(..) | hir
::ExprKind
::DropTemps(..) |
617 hir
::ExprKind
::Array(..) | hir
::ExprKind
::Tup(..) |
618 hir
::ExprKind
::Binary(..) |
619 hir
::ExprKind
::Block(..) | hir
::ExprKind
::Loop(..) | hir
::ExprKind
::Match(..) |
620 hir
::ExprKind
::Lit(..) | hir
::ExprKind
::Break(..) |
621 hir
::ExprKind
::Continue(..) | hir
::ExprKind
::Struct(..) | hir
::ExprKind
::Repeat(..) |
622 hir
::ExprKind
::InlineAsm(..) | hir
::ExprKind
::Box(..) | hir
::ExprKind
::Err
=> {
623 Ok(self.cat_rvalue_node(expr
.hir_id
, expr
.span
, expr_ty
))
628 pub fn cat_res(&self,
633 -> McResult
<cmt_
<'tcx
>> {
634 debug
!("cat_res: id={:?} expr={:?} def={:?}",
635 hir_id
, expr_ty
, res
);
638 Res
::Def(DefKind
::Ctor(..), _
)
639 | Res
::Def(DefKind
::Const
, _
)
640 | Res
::Def(DefKind
::ConstParam
, _
)
641 | Res
::Def(DefKind
::AssocConst
, _
)
642 | Res
::Def(DefKind
::Fn
, _
)
643 | Res
::Def(DefKind
::Method
, _
)
644 | Res
::SelfCtor(..) => {
645 Ok(self.cat_rvalue_node(hir_id
, span
, expr_ty
))
648 Res
::Def(DefKind
::Static
, def_id
) => {
649 // `#[thread_local]` statics may not outlive the current function, but
650 // they also cannot be moved out of.
651 let is_thread_local
= self.tcx
.get_attrs(def_id
)[..]
653 .any(|attr
| attr
.check_name(sym
::thread_local
));
655 let cat
= if is_thread_local
{
656 Categorization
::ThreadLocal
658 Categorization
::StaticItem
665 mutbl
: match self.tcx
.static_mutability(def_id
).unwrap() {
666 hir
::MutImmutable
=> McImmutable
,
667 hir
::MutMutable
=> McDeclared
,
674 Res
::Local(var_id
) => {
675 if self.upvars
.map_or(false, |upvars
| upvars
.contains_key(&var_id
)) {
676 self.cat_upvar(hir_id
, span
, var_id
)
681 cat
: Categorization
::Local(var_id
),
682 mutbl
: MutabilityCategory
::from_local(self.tcx
, self.tables
, var_id
),
689 def
=> span_bug
!(span
, "unexpected definition in memory categorization: {:?}", def
)
693 // Categorize an upvar, complete with invisible derefs of closure
694 // environment and upvar reference as appropriate.
700 ) -> McResult
<cmt_
<'tcx
>> {
701 // An upvar can have up to 3 components. We translate first to a
702 // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the
703 // field from the environment.
705 // `Categorization::Upvar`. Next, we add a deref through the implicit
706 // environment pointer with an anonymous free region 'env and
707 // appropriate borrow kind for closure kinds that take self by
708 // reference. Finally, if the upvar was captured
709 // by-reference, we add a deref through that reference. The
710 // region of this reference is an inference variable 'up that
711 // was previously generated and recorded in the upvar borrow
712 // map. The borrow kind bk is inferred by based on how the
715 // This results in the following table for concrete closure
719 // ---------------+----------------------+-------------------------------
720 // Fn | copied -> &'env | upvar -> &'env -> &'up bk
721 // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
722 // FnOnce | copied | upvar -> &'up bk
724 let closure_expr_def_id
= self.body_owner
;
725 let fn_hir_id
= self.tcx
.hir().local_def_id_to_hir_id(
726 LocalDefId
::from_def_id(closure_expr_def_id
),
728 let ty
= self.node_ty(fn_hir_id
)?
;
729 let kind
= match ty
.kind
{
730 ty
::Generator(..) => ty
::ClosureKind
::FnOnce
,
731 ty
::Closure(closure_def_id
, substs
) => {
733 // During upvar inference we may not know the
734 // closure kind, just use the LATTICE_BOTTOM value.
739 ).unwrap_or(ty
::ClosureKind
::LATTICE_BOTTOM
),
742 substs
.as_closure().kind(closure_def_id
, self.tcx
),
745 _
=> span_bug
!(span
, "unexpected type for fn in mem_categorization: {:?}", ty
),
748 let upvar_id
= ty
::UpvarId
{
749 var_path
: ty
::UpvarPath { hir_id: var_id }
,
750 closure_expr_id
: closure_expr_def_id
.to_local(),
753 let var_ty
= self.node_ty(var_id
)?
;
755 // Mutability of original variable itself
756 let var_mutbl
= MutabilityCategory
::from_local(self.tcx
, self.tables
, var_id
);
758 // Construct the upvar. This represents access to the field
759 // from the environment (perhaps we should eventually desugar
760 // this field further, but it will do for now).
761 let cmt_result
= cmt_
{
764 cat
: Categorization
::Upvar(Upvar {id: upvar_id, kind: kind}
),
770 // If this is a `FnMut` or `Fn` closure, then the above is
771 // conceptually a `&mut` or `&` reference, so we have to add a
773 let cmt_result
= match kind
{
774 ty
::ClosureKind
::FnOnce
=> {
777 ty
::ClosureKind
::FnMut
=> {
778 self.env_deref(hir_id
, span
, upvar_id
, var_mutbl
, ty
::MutBorrow
, cmt_result
)
780 ty
::ClosureKind
::Fn
=> {
781 self.env_deref(hir_id
, span
, upvar_id
, var_mutbl
, ty
::ImmBorrow
, cmt_result
)
785 // If this is a by-ref capture, then the upvar we loaded is
786 // actually a reference, so we have to add an implicit deref
788 let upvar_capture
= self.tables
.upvar_capture(upvar_id
);
789 let cmt_result
= match upvar_capture
{
790 ty
::UpvarCapture
::ByValue
=> {
793 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
794 let ptr
= BorrowedPtr(upvar_borrow
.kind
, upvar_borrow
.region
);
798 cat
: Categorization
::Deref(Rc
::new(cmt_result
), ptr
),
799 mutbl
: MutabilityCategory
::from_borrow_kind(upvar_borrow
.kind
),
801 note
: NoteUpvarRef(upvar_id
)
806 let ret
= cmt_result
;
807 debug
!("cat_upvar ret={:?}", ret
);
814 upvar_id
: ty
::UpvarId
,
815 upvar_mutbl
: MutabilityCategory
,
816 env_borrow_kind
: ty
::BorrowKind
,
817 cmt_result
: cmt_
<'tcx
>)
820 // Region of environment pointer
821 let env_region
= self.tcx
.mk_region(ty
::ReFree(ty
::FreeRegion
{
822 // The environment of a closure is guaranteed to
823 // outlive any bindings introduced in the body of the
825 scope
: upvar_id
.closure_expr_id
.to_def_id(),
826 bound_region
: ty
::BrEnv
829 let env_ptr
= BorrowedPtr(env_borrow_kind
, env_region
);
831 let var_ty
= cmt_result
.ty
;
833 // We need to add the env deref. This means
834 // that the above is actually immutable and
835 // has a ref type. However, nothing should
836 // actually look at the type, so we can get
837 // away with stuffing a `Error` in there
838 // instead of bothering to construct a proper
840 let cmt_result
= cmt_
{
842 ty
: self.tcx
.types
.err
,
846 let mut deref_mutbl
= MutabilityCategory
::from_borrow_kind(env_borrow_kind
);
848 // Issue #18335. If variable is declared as immutable, override the
849 // mutability from the environment and substitute an `&T` anyway.
851 McImmutable
=> { deref_mutbl = McImmutable; }
852 McDeclared
| McInherited
=> { }
858 cat
: Categorization
::Deref(Rc
::new(cmt_result
), env_ptr
),
861 note
: NoteClosureEnv(upvar_id
)
864 debug
!("env_deref ret {:?}", ret
);
869 pub fn cat_rvalue_node(&self,
874 debug
!("cat_rvalue_node(id={:?}, span={:?}, expr_ty={:?})",
875 hir_id
, span
, expr_ty
);
877 let ret
= self.cat_rvalue(hir_id
, span
, expr_ty
);
878 debug
!("cat_rvalue_node ret {:?}", ret
);
882 pub fn cat_rvalue(&self,
883 cmt_hir_id
: hir
::HirId
,
885 expr_ty
: Ty
<'tcx
>) -> cmt_
<'tcx
> {
889 cat
:Categorization
::Rvalue
,
894 debug
!("cat_rvalue ret {:?}", ret
);
898 pub fn cat_field
<N
: HirNode
>(&self,
906 hir_id
: node
.hir_id(),
908 mutbl
: base_cmt
.mutbl
.inherit(),
909 cat
: Categorization
::Interior(base_cmt
,
910 InteriorField(FieldIndex(f_index
, f_ident
.name
))),
914 debug
!("cat_field ret {:?}", ret
);
918 fn cat_overloaded_place(
923 ) -> McResult
<cmt_
<'tcx
>> {
924 debug
!("cat_overloaded_place(expr={:?}, base={:?}, note={:?})",
929 // Reconstruct the output assuming it's a reference with the
930 // same region and mutability as the receiver. This holds for
931 // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
932 let place_ty
= self.expr_ty(expr
)?
;
933 let base_ty
= self.expr_ty_adjusted(base
)?
;
935 let (region
, mutbl
) = match base_ty
.kind
{
936 ty
::Ref(region
, _
, mutbl
) => (region
, mutbl
),
937 _
=> span_bug
!(expr
.span
, "cat_overloaded_place: base is not a reference")
939 let ref_ty
= self.tcx
.mk_ref(region
, ty
::TypeAndMut
{
944 let base_cmt
= Rc
::new(self.cat_rvalue_node(expr
.hir_id
, expr
.span
, ref_ty
));
945 self.cat_deref(expr
, base_cmt
, note
)
953 ) -> McResult
<cmt_
<'tcx
>> {
954 debug
!("cat_deref: base_cmt={:?}", base_cmt
);
956 let base_cmt_ty
= base_cmt
.ty
;
957 let deref_ty
= match base_cmt_ty
.builtin_deref(true) {
960 debug
!("explicit deref of non-derefable type: {:?}", base_cmt_ty
);
965 let ptr
= match base_cmt
.ty
.kind
{
966 ty
::Adt(def
, ..) if def
.is_box() => Unique
,
967 ty
::RawPtr(ref mt
) => UnsafePtr(mt
.mutbl
),
968 ty
::Ref(r
, _
, mutbl
) => {
969 let bk
= ty
::BorrowKind
::from_mutbl(mutbl
);
972 _
=> bug
!("unexpected type in cat_deref: {:?}", base_cmt
.ty
)
975 hir_id
: node
.hir_id(),
977 // For unique ptrs, we inherit mutability from the owning reference.
978 mutbl
: MutabilityCategory
::from_pointer_kind(base_cmt
.mutbl
, ptr
),
979 cat
: Categorization
::Deref(base_cmt
, ptr
),
983 debug
!("cat_deref ret {:?}", ret
);
987 fn cat_index
<N
: HirNode
>(&self,
990 element_ty
: Ty
<'tcx
>,
991 context
: InteriorOffsetKind
)
992 -> McResult
<cmt_
<'tcx
>> {
993 //! Creates a cmt for an indexing operation (`[]`).
995 //! One subtle aspect of indexing that may not be
996 //! immediately obvious: for anything other than a fixed-length
997 //! vector, an operation like `x[y]` actually consists of two
998 //! disjoint (from the point of view of borrowck) operations.
999 //! The first is a deref of `x` to create a pointer `p` that points
1000 //! at the first element in the array. The second operation is
1001 //! an index which adds `y*sizeof(T)` to `p` to obtain the
1002 //! pointer to `x[y]`. `cat_index` will produce a resulting
1003 //! cmt containing both this deref and the indexing,
1004 //! presuming that `base_cmt` is not of fixed-length type.
1007 //! - `elt`: the HIR node being indexed
1008 //! - `base_cmt`: the cmt of `elt`
1010 let interior_elem
= InteriorElement(context
);
1011 let ret
= self.cat_imm_interior(elt
, base_cmt
, element_ty
, interior_elem
);
1012 debug
!("cat_index ret {:?}", ret
);
1016 pub fn cat_imm_interior
<N
:HirNode
>(&self,
1018 base_cmt
: cmt
<'tcx
>,
1019 interior_ty
: Ty
<'tcx
>,
1020 interior
: InteriorKind
)
1023 hir_id
: node
.hir_id(),
1025 mutbl
: base_cmt
.mutbl
.inherit(),
1026 cat
: Categorization
::Interior(base_cmt
, interior
),
1030 debug
!("cat_imm_interior ret={:?}", ret
);
1034 pub fn cat_downcast_if_needed
<N
:HirNode
>(&self,
1036 base_cmt
: cmt
<'tcx
>,
1039 // univariant enums do not need downcasts
1040 let base_did
= self.tcx
.parent(variant_did
).unwrap();
1041 if self.tcx
.adt_def(base_did
).variants
.len() != 1 {
1042 let base_ty
= base_cmt
.ty
;
1043 let ret
= Rc
::new(cmt_
{
1044 hir_id
: node
.hir_id(),
1046 mutbl
: base_cmt
.mutbl
.inherit(),
1047 cat
: Categorization
::Downcast(base_cmt
, variant_did
),
1051 debug
!("cat_downcast ret={:?}", ret
);
1054 debug
!("cat_downcast univariant={:?}", base_cmt
);
1059 pub fn cat_pattern
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &hir
::Pat
, mut op
: F
) -> McResult
<()>
1060 where F
: FnMut(cmt
<'tcx
>, &hir
::Pat
),
1062 self.cat_pattern_(cmt
, pat
, &mut op
)
1065 // FIXME(#19596) This is a workaround, but there should be a better way to do this
1066 fn cat_pattern_
<F
>(&self, mut cmt
: cmt
<'tcx
>, pat
: &hir
::Pat
, op
: &mut F
) -> McResult
<()>
1067 where F
: FnMut(cmt
<'tcx
>, &hir
::Pat
)
1069 // Here, `cmt` is the categorization for the value being
1070 // matched and pat is the pattern it is being matched against.
1072 // In general, the way that this works is that we walk down
1073 // the pattern, constructing a cmt that represents the path
1074 // that will be taken to reach the value being matched.
1076 // When we encounter named bindings, we take the cmt that has
1077 // been built up and pass it off to guarantee_valid() so that
1078 // we can be sure that the binding will remain valid for the
1079 // duration of the arm.
1081 // (*2) There is subtlety concerning the correspondence between
1082 // pattern ids and types as compared to *expression* ids and
1083 // types. This is explained briefly. on the definition of the
1084 // type `cmt`, so go off and read what it says there, then
1085 // come back and I'll dive into a bit more detail here. :) OK,
1088 // In general, the id of the cmt should be the node that
1089 // "produces" the value---patterns aren't executable code
1090 // exactly, but I consider them to "execute" when they match a
1091 // value, and I consider them to produce the value that was
1092 // matched. So if you have something like:
1094 // (FIXME: `@@3` is not legal code anymore!)
1101 // In this case, the cmt and the relevant ids would be:
1103 // CMT Id Type of Id Type of cmt
1106 // ^~~~~~~^ `x` from discr @@int @@int
1107 // ^~~~~~~~~~^ `@@y` pattern node @@int @int
1108 // ^~~~~~~~~~~~~^ `@y` pattern node @int int
1110 // You can see that the types of the id and the cmt are in
1111 // sync in the first line, because that id is actually the id
1112 // of an expression. But once we get to pattern ids, the types
1113 // step out of sync again. So you'll see below that we always
1114 // get the type of the *subpattern* and use that.
1116 debug
!("cat_pattern(pat={:?}, cmt={:?})", pat
, cmt
);
1118 // If (pattern) adjustments are active for this pattern, adjust the `cmt` correspondingly.
1119 // `cmt`s are constructed differently from patterns. For example, in
1123 // &&Some(x, ) => { ... },
1128 // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
1129 // corresponding `cmt` we start with a `cmt` for `foo`, and then, by traversing the
1130 // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
1132 // `&&Some(x,)` `cmt_foo`
1133 // `&Some(x,)` `deref { cmt_foo}`
1134 // `Some(x,)` `deref { deref { cmt_foo }}`
1135 // (x,)` `field0 { deref { deref { cmt_foo }}}` <- resulting cmt
1137 // The above example has no adjustments. If the code were instead the (after adjustments,
1138 // equivalent) version
1142 // Some(x, ) => { ... },
1147 // Then we see that to get the same result, we must start with `deref { deref { cmt_foo }}`
1148 // instead of `cmt_foo` since the pattern is now `Some(x,)` and not `&&Some(x,)`, even
1149 // though its assigned type is that of `&&Some(x,)`.
1150 for _
in 0..self.tables
1156 debug
!("cat_pattern: applying adjustment to cmt={:?}", cmt
);
1157 cmt
= Rc
::new(self.cat_deref(pat
, cmt
, NoteNone
)?
);
1159 let cmt
= cmt
; // lose mutability
1160 debug
!("cat_pattern: applied adjustment derefs to get cmt={:?}", cmt
);
1162 // Invoke the callback, but only now, after the `cmt` has adjusted.
1164 // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
1165 // case, the initial `cmt` will be that for `&Some(3)` and the pattern is `Some(x)`. We
1166 // don't want to call `op` with these incompatible values. As written, what happens instead
1167 // is that `op` is called with the adjusted cmt (that for `*&Some(3)`) and the pattern
1168 // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
1169 // result in the cmt `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
1170 // that (where the `ref` on `x` is implied).
1171 op(cmt
.clone(), pat
);
1174 PatKind
::TupleStruct(ref qpath
, ref subpats
, ddpos
) => {
1175 let res
= self.tables
.qpath_res(qpath
, pat
.hir_id
);
1176 let (cmt
, expected_len
) = match res
{
1178 debug
!("access to unresolvable pattern {:?}", pat
);
1181 Res
::Def(DefKind
::Ctor(CtorOf
::Variant
, CtorKind
::Fn
), variant_ctor_did
) => {
1182 let variant_did
= self.tcx
.parent(variant_ctor_did
).unwrap();
1183 let enum_did
= self.tcx
.parent(variant_did
).unwrap();
1184 (self.cat_downcast_if_needed(pat
, cmt
, variant_did
),
1185 self.tcx
.adt_def(enum_did
)
1186 .variant_with_ctor_id(variant_ctor_did
).fields
.len())
1188 Res
::Def(DefKind
::Ctor(CtorOf
::Struct
, CtorKind
::Fn
), _
)
1189 | Res
::SelfCtor(..) => {
1190 let ty
= self.pat_ty_unadjusted(&pat
)?
;
1192 ty
::Adt(adt_def
, _
) => {
1193 (cmt
, adt_def
.non_enum_variant().fields
.len())
1197 "tuple struct pattern unexpected type {:?}", ty
);
1203 "tuple struct pattern didn't resolve to variant or struct {:?} at {:?}",
1207 self.tcx
.sess
.delay_span_bug(pat
.span
, &format
!(
1208 "tuple struct pattern didn't resolve to variant or struct {:?}",
1215 for (i
, subpat
) in subpats
.iter().enumerate_and_adjust(expected_len
, ddpos
) {
1216 let subpat_ty
= self.pat_ty_adjusted(&subpat
)?
; // see (*2)
1217 let interior
= InteriorField(FieldIndex(i
, sym
::integer(i
)));
1218 let subcmt
= Rc
::new(
1219 self.cat_imm_interior(pat
, cmt
.clone(), subpat_ty
, interior
));
1220 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1224 PatKind
::Struct(ref qpath
, ref field_pats
, _
) => {
1225 // {f1: p1, ..., fN: pN}
1226 let res
= self.tables
.qpath_res(qpath
, pat
.hir_id
);
1227 let cmt
= match res
{
1229 debug
!("access to unresolvable pattern {:?}", pat
);
1232 Res
::Def(DefKind
::Ctor(CtorOf
::Variant
, _
), variant_ctor_did
) => {
1233 let variant_did
= self.tcx
.parent(variant_ctor_did
).unwrap();
1234 self.cat_downcast_if_needed(pat
, cmt
, variant_did
)
1236 Res
::Def(DefKind
::Variant
, variant_did
) => {
1237 self.cat_downcast_if_needed(pat
, cmt
, variant_did
)
1242 for fp
in field_pats
{
1243 let field_ty
= self.pat_ty_adjusted(&fp
.pat
)?
; // see (*2)
1244 let f_index
= self.tcx
.field_index(fp
.hir_id
, self.tables
);
1245 let cmt_field
= Rc
::new(self.cat_field(pat
, cmt
.clone(), f_index
,
1246 fp
.ident
, field_ty
));
1247 self.cat_pattern_(cmt_field
, &fp
.pat
, op
)?
;
1251 PatKind
::Or(ref pats
) => {
1253 self.cat_pattern_(cmt
.clone(), &pat
, op
)?
;
1257 PatKind
::Binding(.., Some(ref subpat
)) => {
1258 self.cat_pattern_(cmt
, &subpat
, op
)?
;
1261 PatKind
::Tuple(ref subpats
, ddpos
) => {
1263 let ty
= self.pat_ty_unadjusted(&pat
)?
;
1264 let expected_len
= match ty
.kind
{
1265 ty
::Tuple(ref tys
) => tys
.len(),
1266 _
=> span_bug
!(pat
.span
, "tuple pattern unexpected type {:?}", ty
),
1268 for (i
, subpat
) in subpats
.iter().enumerate_and_adjust(expected_len
, ddpos
) {
1269 let subpat_ty
= self.pat_ty_adjusted(&subpat
)?
; // see (*2)
1270 let interior
= InteriorField(FieldIndex(i
, sym
::integer(i
)));
1271 let subcmt
= Rc
::new(
1272 self.cat_imm_interior(pat
, cmt
.clone(), subpat_ty
, interior
));
1273 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1277 PatKind
::Box(ref subpat
) | PatKind
::Ref(ref subpat
, _
) => {
1278 // box p1, &p1, &mut p1. we can ignore the mutability of
1279 // PatKind::Ref since that information is already contained
1281 let subcmt
= Rc
::new(self.cat_deref(pat
, cmt
, NoteNone
)?
);
1282 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1285 PatKind
::Slice(ref before
, ref slice
, ref after
) => {
1286 let element_ty
= match cmt
.ty
.builtin_index() {
1289 debug
!("explicit index of non-indexable type {:?}", cmt
);
1293 let context
= InteriorOffsetKind
::Pattern
;
1294 let elt_cmt
= Rc
::new(self.cat_index(pat
, cmt
, element_ty
, context
)?
);
1295 for before_pat
in before
{
1296 self.cat_pattern_(elt_cmt
.clone(), &before_pat
, op
)?
;
1298 if let Some(ref slice_pat
) = *slice
{
1299 self.cat_pattern_(elt_cmt
.clone(), &slice_pat
, op
)?
;
1301 for after_pat
in after
{
1302 self.cat_pattern_(elt_cmt
.clone(), &after_pat
, op
)?
;
1306 PatKind
::Path(_
) | PatKind
::Binding(.., None
) |
1307 PatKind
::Lit(..) | PatKind
::Range(..) | PatKind
::Wild
=> {
1316 #[derive(Clone, Debug)]
1317 pub enum Aliasability
{
1318 FreelyAliasable(AliasableReason
),
1320 ImmutableUnique(Box
<Aliasability
>),
1323 #[derive(Copy, Clone, Debug)]
1324 pub enum AliasableReason
{
1330 impl<'tcx
> cmt_
<'tcx
> {
1331 pub fn guarantor(&self) -> cmt_
<'tcx
> {
1332 //! Returns `self` after stripping away any derefs or
1333 //! interior content. The return value is basically the `cmt` which
1334 //! determines how long the value in `self` remains live.
1337 Categorization
::Rvalue
|
1338 Categorization
::StaticItem
|
1339 Categorization
::ThreadLocal
|
1340 Categorization
::Local(..) |
1341 Categorization
::Deref(_
, UnsafePtr(..)) |
1342 Categorization
::Deref(_
, BorrowedPtr(..)) |
1343 Categorization
::Upvar(..) => {
1346 Categorization
::Downcast(ref b
, _
) |
1347 Categorization
::Interior(ref b
, _
) |
1348 Categorization
::Deref(ref b
, Unique
) => {
1354 /// Returns `FreelyAliasable(_)` if this place represents a freely aliasable pointer type.
1355 pub fn freely_aliasable(&self) -> Aliasability
{
1356 // Maybe non-obvious: copied upvars can only be considered
1357 // non-aliasable in once closures, since any other kind can be
1358 // aliased and eventually recused.
1361 Categorization
::Deref(ref b
, BorrowedPtr(ty
::MutBorrow
, _
)) |
1362 Categorization
::Deref(ref b
, BorrowedPtr(ty
::UniqueImmBorrow
, _
)) |
1363 Categorization
::Deref(ref b
, Unique
) |
1364 Categorization
::Downcast(ref b
, _
) |
1365 Categorization
::Interior(ref b
, _
) => {
1366 // Aliasability depends on base cmt
1367 b
.freely_aliasable()
1370 Categorization
::Rvalue
|
1371 Categorization
::ThreadLocal
|
1372 Categorization
::Local(..) |
1373 Categorization
::Upvar(..) |
1374 Categorization
::Deref(_
, UnsafePtr(..)) => { // yes, it's aliasable, but...
1378 Categorization
::StaticItem
=> {
1379 if self.mutbl
.is_mutable() {
1380 FreelyAliasable(AliasableStaticMut
)
1382 FreelyAliasable(AliasableStatic
)
1386 Categorization
::Deref(_
, BorrowedPtr(ty
::ImmBorrow
, _
)) => {
1387 FreelyAliasable(AliasableBorrowed
)
1392 // Digs down through one or two layers of deref and grabs the
1393 // Categorization of the cmt for the upvar if a note indicates there is
1395 pub fn upvar_cat(&self) -> Option
<&Categorization
<'tcx
>> {
1397 NoteClosureEnv(..) | NoteUpvarRef(..) => {
1398 Some(match self.cat
{
1399 Categorization
::Deref(ref inner
, _
) => {
1401 Categorization
::Deref(ref inner
, _
) => &inner
.cat
,
1402 Categorization
::Upvar(..) => &inner
.cat
,
1409 NoteIndex
| NoteNone
=> None
1413 pub fn descriptive_string(&self, tcx
: TyCtxt
<'_
>) -> Cow
<'
static, str> {
1415 Categorization
::StaticItem
=> {
1416 "static item".into()
1418 Categorization
::ThreadLocal
=> {
1419 "thread-local static item".into()
1421 Categorization
::Rvalue
=> {
1424 Categorization
::Local(vid
) => {
1425 if tcx
.hir().is_argument(vid
) {
1431 Categorization
::Deref(_
, pk
) => {
1432 match self.upvar_cat() {
1433 Some(&Categorization
::Upvar(ref var
)) => {
1434 var
.to_string().into()
1443 "dereference of raw pointer"
1445 BorrowedPtr(..) => {
1447 NoteIndex
=> "indexed content",
1448 _
=> "borrowed content"
1455 Categorization
::Interior(_
, InteriorField(..)) => {
1458 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Index
)) => {
1459 "indexed content".into()
1461 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
)) => {
1462 "pattern-bound indexed content".into()
1464 Categorization
::Upvar(ref var
) => {
1465 var
.to_string().into()
1467 Categorization
::Downcast(ref cmt
, _
) => {
1468 cmt
.descriptive_string(tcx
).into()
1474 pub fn ptr_sigil(ptr
: PointerKind
<'_
>) -> &'
static str {
1477 BorrowedPtr(ty
::ImmBorrow
, _
) => "&",
1478 BorrowedPtr(ty
::MutBorrow
, _
) => "&mut",
1479 BorrowedPtr(ty
::UniqueImmBorrow
, _
) => "&unique",
1480 UnsafePtr(_
) => "*",
1484 impl fmt
::Debug
for InteriorKind
{
1485 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1487 InteriorField(FieldIndex(_
, info
)) => write
!(f
, "{}", info
),
1488 InteriorElement(..) => write
!(f
, "[]"),
1493 impl fmt
::Debug
for Upvar
{
1494 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1495 write
!(f
, "{:?}/{:?}", self.id
, self.kind
)
1499 impl fmt
::Display
for Upvar
{
1500 fn fmt(&self, f
: &mut fmt
::Formatter
<'_
>) -> fmt
::Result
{
1501 let kind
= match self.kind
{
1502 ty
::ClosureKind
::Fn
=> "Fn",
1503 ty
::ClosureKind
::FnMut
=> "FnMut",
1504 ty
::ClosureKind
::FnOnce
=> "FnOnce",
1506 write
!(f
, "captured outer variable in an `{}` closure", kind
)