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
::*;
71 use self::Aliasability
::*;
73 use hir
::def_id
::DefId
;
74 use hir
::map
as hir_map
;
76 use hir
::def
::{Def, CtorKind}
;
78 use ty
::{self, Ty, TyCtxt}
;
80 use hir
::{MutImmutable, MutMutable, PatKind}
;
81 use hir
::pat_util
::EnumerateAndAdjustIterator
;
89 #[derive(Clone, PartialEq)]
90 pub enum Categorization
<'tcx
> {
91 // temporary val, argument is its scope
92 Rvalue(&'tcx ty
::Region
, &'tcx ty
::Region
),
94 Upvar(Upvar
), // upvar referenced by closure env
95 Local(ast
::NodeId
), // local variable
96 Deref(cmt
<'tcx
>, usize, PointerKind
<'tcx
>), // deref of a ptr
97 Interior(cmt
<'tcx
>, InteriorKind
), // something interior: field, tuple, etc
98 Downcast(cmt
<'tcx
>, 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
<'tcx
> {
117 BorrowedPtr(ty
::BorrowKind
, &'tcx ty
::Region
),
120 UnsafePtr(hir
::Mutability
),
122 /// Implicit deref of the `&T` that results from an overloaded index `[]`.
123 Implicit(ty
::BorrowKind
, &'tcx 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 impl<'tcx
> cmt_
<'tcx
> {
198 pub fn get_field(&self, name
: ast
::Name
) -> Option
<DefId
> {
200 Categorization
::Deref(ref cmt
, ..) |
201 Categorization
::Interior(ref cmt
, _
) |
202 Categorization
::Downcast(ref cmt
, _
) => {
203 if let Categorization
::Local(_
) = cmt
.cat
{
204 if let ty
::TyAdt(def
, _
) = self.ty
.sty
{
206 return def
.struct_variant().find_field_named(name
).map(|x
| x
.did
);
218 pub fn get_field_name(&self) -> Option
<ast
::Name
> {
220 Categorization
::Interior(_
, ref ik
) => {
221 if let InteriorKind
::InteriorField(FieldName
::NamedField(name
)) = *ik
{
227 Categorization
::Deref(ref cmt
, ..) |
228 Categorization
::Downcast(ref cmt
, _
) => {
235 pub fn get_arg_if_immutable(&self, map
: &hir_map
::Map
) -> Option
<ast
::NodeId
> {
237 Categorization
::Deref(ref cmt
, ..) |
238 Categorization
::Interior(ref cmt
, _
) |
239 Categorization
::Downcast(ref cmt
, _
) => {
240 if let Categorization
::Local(nid
) = cmt
.cat
{
241 if let ty
::TyAdt(_
, _
) = self.ty
.sty
{
242 if let ty
::TyRef(_
, ty
::TypeAndMut{mutbl: MutImmutable, ..}
) = cmt
.ty
.sty
{
248 cmt
.get_arg_if_immutable(map
)
257 fn id(&self) -> ast
::NodeId
;
258 fn span(&self) -> Span
;
261 impl ast_node
for hir
::Expr
{
262 fn id(&self) -> ast
::NodeId { self.id }
263 fn span(&self) -> Span { self.span }
266 impl ast_node
for hir
::Pat
{
267 fn id(&self) -> ast
::NodeId { self.id }
268 fn span(&self) -> Span { self.span }
271 #[derive(Copy, Clone)]
272 pub struct MemCategorizationContext
<'a
, 'gcx
: 'a
+'tcx
, 'tcx
: 'a
> {
273 pub infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
274 options
: MemCategorizationOptions
,
277 #[derive(Copy, Clone, Default)]
278 pub struct MemCategorizationOptions
{
279 // If true, then when analyzing a closure upvar, if the closure
280 // has a missing kind, we treat it like a Fn closure. When false,
281 // we ICE if the closure has a missing kind. Should be false
282 // except during closure kind inference. It is used by the
283 // mem-categorization code to be able to have stricter assertions
284 // (which are always true except during upvar inference).
285 pub during_closure_kind_inference
: bool
,
288 pub type McResult
<T
> = Result
<T
, ()>;
290 impl MutabilityCategory
{
291 pub fn from_mutbl(m
: hir
::Mutability
) -> MutabilityCategory
{
293 MutImmutable
=> McImmutable
,
294 MutMutable
=> McDeclared
296 debug
!("MutabilityCategory::{}({:?}) => {:?}",
297 "from_mutbl", m
, ret
);
301 pub fn from_borrow_kind(borrow_kind
: ty
::BorrowKind
) -> MutabilityCategory
{
302 let ret
= match borrow_kind
{
303 ty
::ImmBorrow
=> McImmutable
,
304 ty
::UniqueImmBorrow
=> McImmutable
,
305 ty
::MutBorrow
=> McDeclared
,
307 debug
!("MutabilityCategory::{}({:?}) => {:?}",
308 "from_borrow_kind", borrow_kind
, ret
);
312 fn from_pointer_kind(base_mutbl
: MutabilityCategory
,
313 ptr
: PointerKind
) -> MutabilityCategory
{
314 let ret
= match ptr
{
318 BorrowedPtr(borrow_kind
, _
) | Implicit(borrow_kind
, _
) => {
319 MutabilityCategory
::from_borrow_kind(borrow_kind
)
322 MutabilityCategory
::from_mutbl(m
)
325 debug
!("MutabilityCategory::{}({:?}, {:?}) => {:?}",
326 "from_pointer_kind", base_mutbl
, ptr
, ret
);
330 fn from_local(tcx
: TyCtxt
, id
: ast
::NodeId
) -> MutabilityCategory
{
331 let ret
= match tcx
.hir
.get(id
) {
332 hir_map
::NodeLocal(p
) => match p
.node
{
333 PatKind
::Binding(bind_mode
, ..) => {
334 if bind_mode
== hir
::BindByValue(hir
::MutMutable
) {
340 _
=> span_bug
!(p
.span
, "expected identifier pattern")
342 _
=> span_bug
!(tcx
.hir
.span(id
), "expected identifier pattern")
344 debug
!("MutabilityCategory::{}(tcx, id={:?}) => {:?}",
345 "from_local", id
, ret
);
349 pub fn inherit(&self) -> MutabilityCategory
{
350 let ret
= match *self {
351 McImmutable
=> McImmutable
,
352 McDeclared
=> McInherited
,
353 McInherited
=> McInherited
,
355 debug
!("{:?}.inherit() => {:?}", self, ret
);
359 pub fn is_mutable(&self) -> bool
{
360 let ret
= match *self {
361 McImmutable
=> false,
365 debug
!("{:?}.is_mutable() => {:?}", self, ret
);
369 pub fn is_immutable(&self) -> bool
{
370 let ret
= match *self {
372 McDeclared
| McInherited
=> false
374 debug
!("{:?}.is_immutable() => {:?}", self, ret
);
378 pub fn to_user_str(&self) -> &'
static str {
380 McDeclared
| McInherited
=> "mutable",
381 McImmutable
=> "immutable",
386 impl<'a
, 'gcx
, 'tcx
> MemCategorizationContext
<'a
, 'gcx
, 'tcx
> {
387 pub fn new(infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>)
388 -> MemCategorizationContext
<'a
, 'gcx
, 'tcx
> {
389 MemCategorizationContext
::with_options(infcx
, MemCategorizationOptions
::default())
392 pub fn with_options(infcx
: &'a InferCtxt
<'a
, 'gcx
, 'tcx
>,
393 options
: MemCategorizationOptions
)
394 -> MemCategorizationContext
<'a
, 'gcx
, 'tcx
> {
395 MemCategorizationContext
{
401 fn tcx(&self) -> TyCtxt
<'a
, 'gcx
, 'tcx
> {
405 fn expr_ty(&self, expr
: &hir
::Expr
) -> McResult
<Ty
<'tcx
>> {
406 match self.infcx
.node_ty(expr
.id
) {
409 debug
!("expr_ty({:?}) yielded Err", expr
);
415 fn expr_ty_adjusted(&self, expr
: &hir
::Expr
) -> McResult
<Ty
<'tcx
>> {
416 self.infcx
.expr_ty_adjusted(expr
)
419 fn node_ty(&self, id
: ast
::NodeId
) -> McResult
<Ty
<'tcx
>> {
420 self.infcx
.node_ty(id
)
423 fn pat_ty(&self, pat
: &hir
::Pat
) -> McResult
<Ty
<'tcx
>> {
424 let base_ty
= self.infcx
.node_ty(pat
.id
)?
;
425 // FIXME (Issue #18207): This code detects whether we are
426 // looking at a `ref x`, and if so, figures out what the type
427 // *being borrowed* is. But ideally we would put in a more
428 // fundamental fix to this conflated use of the node id.
429 let ret_ty
= match pat
.node
{
430 PatKind
::Binding(hir
::BindByRef(_
), ..) => {
431 // a bind-by-ref means that the base_ty will be the type of the ident itself,
432 // but what we want here is the type of the underlying value being borrowed.
433 // So peel off one-level, turning the &T into T.
434 match base_ty
.builtin_deref(false, ty
::NoPreference
) {
436 None
=> { return Err(()); }
441 debug
!("pat_ty(pat={:?}) base_ty={:?} ret_ty={:?}",
442 pat
, base_ty
, ret_ty
);
446 pub fn cat_expr(&self, expr
: &hir
::Expr
) -> McResult
<cmt
<'tcx
>> {
447 match self.infcx
.tables
.borrow().adjustments
.get(&expr
.id
) {
450 self.cat_expr_unadjusted(expr
)
453 Some(adjustment
) => {
454 match adjustment
.kind
{
455 adjustment
::Adjust
::DerefRef
{
460 // Equivalent to *expr or something similar.
461 self.cat_expr_autoderefd(expr
, autoderefs
)
464 adjustment
::Adjust
::NeverToAny
|
465 adjustment
::Adjust
::ReifyFnPointer
|
466 adjustment
::Adjust
::UnsafeFnPointer
|
467 adjustment
::Adjust
::ClosureFnPointer
|
468 adjustment
::Adjust
::MutToConstPointer
|
469 adjustment
::Adjust
::DerefRef {..}
=> {
470 debug
!("cat_expr({:?}): {:?}",
473 // Result is an rvalue.
474 let expr_ty
= self.expr_ty_adjusted(expr
)?
;
475 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
482 pub fn cat_expr_autoderefd(&self,
485 -> McResult
<cmt
<'tcx
>> {
486 let mut cmt
= self.cat_expr_unadjusted(expr
)?
;
487 debug
!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
490 for deref
in 1..autoderefs
+ 1 {
491 cmt
= self.cat_deref(expr
, cmt
, deref
)?
;
496 pub fn cat_expr_unadjusted(&self, expr
: &hir
::Expr
) -> McResult
<cmt
<'tcx
>> {
497 debug
!("cat_expr: id={} expr={:?}", expr
.id
, expr
);
499 let expr_ty
= self.expr_ty(expr
)?
;
501 hir
::ExprUnary(hir
::UnDeref
, ref e_base
) => {
502 let base_cmt
= self.cat_expr(&e_base
)?
;
503 self.cat_deref(expr
, base_cmt
, 0)
506 hir
::ExprField(ref base
, f_name
) => {
507 let base_cmt
= self.cat_expr(&base
)?
;
508 debug
!("cat_expr(cat_field): id={} expr={:?} base={:?}",
512 Ok(self.cat_field(expr
, base_cmt
, f_name
.node
, expr_ty
))
515 hir
::ExprTupField(ref base
, idx
) => {
516 let base_cmt
= self.cat_expr(&base
)?
;
517 Ok(self.cat_tup_field(expr
, base_cmt
, idx
.node
, expr_ty
))
520 hir
::ExprIndex(ref base
, _
) => {
521 let method_call
= ty
::MethodCall
::expr(expr
.id());
522 match self.infcx
.node_method_ty(method_call
) {
524 // If this is an index implemented by a method call, then it
525 // will include an implicit deref of the result.
526 let ret_ty
= self.overloaded_method_return_ty(method_ty
);
528 // The index method always returns an `&T`, so
529 // dereference it to find the result type.
530 let elem_ty
= match ret_ty
.sty
{
531 ty
::TyRef(_
, mt
) => mt
.ty
,
533 debug
!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
539 // The call to index() returns a `&T` value, which
540 // is an rvalue. That is what we will be
542 let base_cmt
= self.cat_rvalue_node(expr
.id(), expr
.span(), ret_ty
);
543 Ok(self.cat_deref_common(expr
, base_cmt
, 1, elem_ty
, true))
546 self.cat_index(expr
, self.cat_expr(&base
)?
, InteriorOffsetKind
::Index
)
551 hir
::ExprPath(ref qpath
) => {
552 let def
= self.infcx
.tables
.borrow().qpath_def(qpath
, expr
.id
);
553 self.cat_def(expr
.id
, expr
.span
, expr_ty
, def
)
556 hir
::ExprType(ref e
, _
) => {
560 hir
::ExprAddrOf(..) | hir
::ExprCall(..) |
561 hir
::ExprAssign(..) | hir
::ExprAssignOp(..) |
562 hir
::ExprClosure(..) | hir
::ExprRet(..) |
564 hir
::ExprMethodCall(..) | hir
::ExprCast(..) |
565 hir
::ExprArray(..) | hir
::ExprTup(..) | hir
::ExprIf(..) |
566 hir
::ExprBinary(..) | hir
::ExprWhile(..) |
567 hir
::ExprBlock(..) | hir
::ExprLoop(..) | hir
::ExprMatch(..) |
568 hir
::ExprLit(..) | hir
::ExprBreak(..) |
569 hir
::ExprAgain(..) | hir
::ExprStruct(..) | hir
::ExprRepeat(..) |
570 hir
::ExprInlineAsm(..) | hir
::ExprBox(..) => {
571 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
576 pub fn cat_def(&self,
581 -> McResult
<cmt
<'tcx
>> {
582 debug
!("cat_def: id={} expr={:?} def={:?}",
586 Def
::StructCtor(..) | Def
::VariantCtor(..) | Def
::Const(..) |
587 Def
::AssociatedConst(..) | Def
::Fn(..) | Def
::Method(..) => {
588 Ok(self.cat_rvalue_node(id
, span
, expr_ty
))
591 Def
::Static(_
, mutbl
) => {
595 cat
:Categorization
::StaticItem
,
596 mutbl
: if mutbl { McDeclared }
else { McImmutable}
,
602 Def
::Upvar(def_id
, _
, fn_node_id
) => {
603 let var_id
= self.tcx().hir
.as_local_node_id(def_id
).unwrap();
604 let ty
= self.node_ty(fn_node_id
)?
;
606 ty
::TyClosure(closure_id
, _
) => {
607 match self.infcx
.closure_kind(closure_id
) {
609 self.cat_upvar(id
, span
, var_id
, fn_node_id
, kind
)
612 if !self.options
.during_closure_kind_inference
{
615 "No closure kind for {:?}",
619 // during closure kind inference, we
620 // don't know the closure kind yet, but
621 // it's ok because we detect that we are
622 // accessing an upvar and handle that
623 // case specially anyhow. Use Fn
625 self.cat_upvar(id
, span
, var_id
, fn_node_id
, ty
::ClosureKind
::Fn
)
632 "Upvar of non-closure {} - {:?}",
639 Def
::Local(def_id
) => {
640 let vid
= self.tcx().hir
.as_local_node_id(def_id
).unwrap();
644 cat
: Categorization
::Local(vid
),
645 mutbl
: MutabilityCategory
::from_local(self.tcx(), vid
),
651 def
=> span_bug
!(span
, "unexpected definition in memory categorization: {:?}", def
)
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 // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the
667 // field from the environment.
669 // `Categorization::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
= 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
: Categorization
::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
::ClosureKind
::FnOnce
=> {
714 ty
::ClosureKind
::FnMut
=> {
715 self.env_deref(id
, span
, upvar_id
, var_mutbl
, ty
::MutBorrow
, cmt_result
)
717 ty
::ClosureKind
::Fn
=> {
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.infcx
.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
: Categorization
::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().hir
.find(upvar_id
.closure_expr_id
) {
763 Some(hir_map
::NodeExpr(e
)) => e
,
768 hir
::ExprClosure(.., body_id
, _
) => body_id
.node_id
,
773 // Region of environment pointer
774 let env_region
= self.tcx().mk_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
: self.tcx().region_maps
.item_extent(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
: Categorization
::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
) -> (&'tcx ty
::Region
, &'tcx ty
::Region
)
826 let (scope
, old_scope
) =
827 self.tcx().region_maps
.old_and_new_temporary_scope(id
);
828 (self.tcx().mk_region(match scope
{
829 Some(scope
) => ty
::ReScope(scope
),
832 self.tcx().mk_region(match old_scope
{
833 Some(scope
) => ty
::ReScope(scope
),
838 pub fn cat_rvalue_node(&self,
843 let promotable
= self.tcx().rvalue_promotable_to_static
.borrow().get(&id
).cloned()
846 // Only promote `[T; 0]` before an RFC for rvalue promotions
848 let promotable
= match expr_ty
.sty
{
849 ty
::TyArray(_
, 0) => true,
850 _
=> promotable
& false
853 // Compute maximum lifetime of this rvalue. This is 'static if
854 // we can promote to a constant, otherwise equal to enclosing temp
856 let (re
, old_re
) = if promotable
{
857 (self.tcx().mk_region(ty
::ReStatic
),
858 self.tcx().mk_region(ty
::ReStatic
))
860 self.temporary_scope(id
)
862 let ret
= self.cat_rvalue(id
, span
, re
, old_re
, expr_ty
);
863 debug
!("cat_rvalue_node ret {:?}", ret
);
867 pub fn cat_rvalue(&self,
870 temp_scope
: &'tcx ty
::Region
,
871 old_temp_scope
: &'tcx ty
::Region
,
872 expr_ty
: Ty
<'tcx
>) -> cmt
<'tcx
> {
873 let ret
= Rc
::new(cmt_
{
876 cat
:Categorization
::Rvalue(temp_scope
, old_temp_scope
),
881 debug
!("cat_rvalue ret {:?}", ret
);
885 pub fn cat_field
<N
:ast_node
>(&self,
891 let ret
= Rc
::new(cmt_
{
894 mutbl
: base_cmt
.mutbl
.inherit(),
895 cat
: Categorization
::Interior(base_cmt
, InteriorField(NamedField(f_name
))),
899 debug
!("cat_field ret {:?}", ret
);
903 pub fn cat_tup_field
<N
:ast_node
>(&self,
909 let ret
= Rc
::new(cmt_
{
912 mutbl
: base_cmt
.mutbl
.inherit(),
913 cat
: Categorization
::Interior(base_cmt
, InteriorField(PositionalField(f_idx
))),
917 debug
!("cat_tup_field ret {:?}", ret
);
921 fn cat_deref
<N
:ast_node
>(&self,
925 -> McResult
<cmt
<'tcx
>> {
926 let method_call
= ty
::MethodCall
{
928 autoderef
: deref_cnt
as u32
930 let method_ty
= self.infcx
.node_method_ty(method_call
);
932 debug
!("cat_deref: method_call={:?} method_ty={:?}",
933 method_call
, method_ty
.map(|ty
| ty
));
935 let base_cmt
= match method_ty
{
938 self.tcx().no_late_bound_regions(&method_ty
.fn_ret()).unwrap();
939 self.cat_rvalue_node(node
.id(), node
.span(), ref_ty
)
943 let base_cmt_ty
= base_cmt
.ty
;
944 match base_cmt_ty
.builtin_deref(true, ty
::NoPreference
) {
946 let ret
= self.cat_deref_common(node
, base_cmt
, deref_cnt
, mt
.ty
, false);
947 debug
!("cat_deref ret {:?}", ret
);
951 debug
!("Explicit deref of non-derefable type: {:?}",
958 fn cat_deref_common
<N
:ast_node
>(&self,
966 let ptr
= match base_cmt
.ty
.sty
{
967 ty
::TyAdt(def
, ..) if def
.is_box() => Unique
,
968 ty
::TyRawPtr(ref mt
) => UnsafePtr(mt
.mutbl
),
969 ty
::TyRef(r
, mt
) => {
970 let bk
= ty
::BorrowKind
::from_mutbl(mt
.mutbl
);
971 if implicit { Implicit(bk, r) }
else { BorrowedPtr(bk, r) }
973 ref ty
=> bug
!("unexpected type in cat_deref_common: {:?}", ty
)
975 let ret
= Rc
::new(cmt_
{
978 // For unique ptrs, we inherit mutability from the owning reference.
979 mutbl
: MutabilityCategory
::from_pointer_kind(base_cmt
.mutbl
, ptr
),
980 cat
: Categorization
::Deref(base_cmt
, deref_cnt
, ptr
),
984 debug
!("cat_deref_common ret {:?}", ret
);
988 pub fn cat_index
<N
:ast_node
>(&self,
990 mut base_cmt
: cmt
<'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 AST node being indexed
1008 //! - `base_cmt`: the cmt of `elt`
1010 let method_call
= ty
::MethodCall
::expr(elt
.id());
1011 let method_ty
= self.infcx
.node_method_ty(method_call
);
1013 let (element_ty
, element_kind
) = match method_ty
{
1014 Some(method_ty
) => {
1015 let ref_ty
= self.overloaded_method_return_ty(method_ty
);
1016 base_cmt
= self.cat_rvalue_node(elt
.id(), elt
.span(), ref_ty
);
1018 (ref_ty
.builtin_deref(false, ty
::NoPreference
).unwrap().ty
,
1019 ElementKind
::OtherElement
)
1022 match base_cmt
.ty
.builtin_index() {
1023 Some(ty
) => (ty
, ElementKind
::VecElement
),
1031 let interior_elem
= InteriorElement(context
, element_kind
);
1033 self.cat_imm_interior(elt
, base_cmt
.clone(), element_ty
, interior_elem
);
1034 debug
!("cat_index ret {:?}", ret
);
1038 pub fn cat_imm_interior
<N
:ast_node
>(&self,
1040 base_cmt
: cmt
<'tcx
>,
1041 interior_ty
: Ty
<'tcx
>,
1042 interior
: InteriorKind
)
1044 let ret
= Rc
::new(cmt_
{
1047 mutbl
: base_cmt
.mutbl
.inherit(),
1048 cat
: Categorization
::Interior(base_cmt
, interior
),
1052 debug
!("cat_imm_interior ret={:?}", ret
);
1056 pub fn cat_downcast
<N
:ast_node
>(&self,
1058 base_cmt
: cmt
<'tcx
>,
1059 downcast_ty
: Ty
<'tcx
>,
1062 let ret
= Rc
::new(cmt_
{
1065 mutbl
: base_cmt
.mutbl
.inherit(),
1066 cat
: Categorization
::Downcast(base_cmt
, variant_did
),
1070 debug
!("cat_downcast ret={:?}", ret
);
1074 pub fn cat_pattern
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &hir
::Pat
, mut op
: F
) -> McResult
<()>
1075 where F
: FnMut(&MemCategorizationContext
<'a
, 'gcx
, 'tcx
>, cmt
<'tcx
>, &hir
::Pat
),
1077 self.cat_pattern_(cmt
, pat
, &mut op
)
1080 // FIXME(#19596) This is a workaround, but there should be a better way to do this
1081 fn cat_pattern_
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &hir
::Pat
, op
: &mut F
) -> McResult
<()>
1082 where F
: FnMut(&MemCategorizationContext
<'a
, 'gcx
, 'tcx
>, cmt
<'tcx
>, &hir
::Pat
)
1084 // Here, `cmt` is the categorization for the value being
1085 // matched and pat is the pattern it is being matched against.
1087 // In general, the way that this works is that we walk down
1088 // the pattern, constructing a cmt that represents the path
1089 // that will be taken to reach the value being matched.
1091 // When we encounter named bindings, we take the cmt that has
1092 // been built up and pass it off to guarantee_valid() so that
1093 // we can be sure that the binding will remain valid for the
1094 // duration of the arm.
1096 // (*2) There is subtlety concerning the correspondence between
1097 // pattern ids and types as compared to *expression* ids and
1098 // types. This is explained briefly. on the definition of the
1099 // type `cmt`, so go off and read what it says there, then
1100 // come back and I'll dive into a bit more detail here. :) OK,
1103 // In general, the id of the cmt should be the node that
1104 // "produces" the value---patterns aren't executable code
1105 // exactly, but I consider them to "execute" when they match a
1106 // value, and I consider them to produce the value that was
1107 // matched. So if you have something like:
1114 // In this case, the cmt and the relevant ids would be:
1116 // CMT Id Type of Id Type of cmt
1119 // ^~~~~~~^ `x` from discr @@int @@int
1120 // ^~~~~~~~~~^ `@@y` pattern node @@int @int
1121 // ^~~~~~~~~~~~~^ `@y` pattern node @int int
1123 // You can see that the types of the id and the cmt are in
1124 // sync in the first line, because that id is actually the id
1125 // of an expression. But once we get to pattern ids, the types
1126 // step out of sync again. So you'll see below that we always
1127 // get the type of the *subpattern* and use that.
1129 debug
!("cat_pattern: {:?} cmt={:?}", pat
, cmt
);
1131 op(self, cmt
.clone(), pat
);
1133 // Note: This goes up here (rather than within the PatKind::TupleStruct arm
1134 // alone) because PatKind::Struct can also refer to variants.
1135 let cmt
= match pat
.node
{
1136 PatKind
::Path(hir
::QPath
::Resolved(_
, ref path
)) |
1137 PatKind
::TupleStruct(hir
::QPath
::Resolved(_
, ref path
), ..) |
1138 PatKind
::Struct(hir
::QPath
::Resolved(_
, ref path
), ..) => {
1140 Def
::Err
=> return Err(()),
1141 Def
::Variant(variant_did
) |
1142 Def
::VariantCtor(variant_did
, ..) => {
1143 // univariant enums do not need downcasts
1144 let enum_did
= self.tcx().parent_def_id(variant_did
).unwrap();
1145 if !self.tcx().lookup_adt_def(enum_did
).is_univariant() {
1146 self.cat_downcast(pat
, cmt
.clone(), cmt
.ty
, variant_did
)
1158 PatKind
::TupleStruct(ref qpath
, ref subpats
, ddpos
) => {
1159 let def
= self.infcx
.tables
.borrow().qpath_def(qpath
, pat
.id
);
1160 let expected_len
= match def
{
1161 Def
::VariantCtor(def_id
, CtorKind
::Fn
) => {
1162 let enum_def
= self.tcx().parent_def_id(def_id
).unwrap();
1163 self.tcx().lookup_adt_def(enum_def
).variant_with_id(def_id
).fields
.len()
1165 Def
::StructCtor(_
, CtorKind
::Fn
) => {
1166 match self.pat_ty(&pat
)?
.sty
{
1167 ty
::TyAdt(adt_def
, _
) => {
1168 adt_def
.struct_variant().fields
.len()
1171 span_bug
!(pat
.span
, "tuple struct pattern unexpected type {:?}", ty
);
1176 span_bug
!(pat
.span
, "tuple struct pattern didn't resolve \
1177 to variant or struct {:?}", def
);
1181 for (i
, subpat
) in subpats
.iter().enumerate_and_adjust(expected_len
, ddpos
) {
1182 let subpat_ty
= self.pat_ty(&subpat
)?
; // see (*2)
1183 let subcmt
= self.cat_imm_interior(pat
, cmt
.clone(), subpat_ty
,
1184 InteriorField(PositionalField(i
)));
1185 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1189 PatKind
::Struct(_
, ref field_pats
, _
) => {
1190 // {f1: p1, ..., fN: pN}
1191 for fp
in field_pats
{
1192 let field_ty
= self.pat_ty(&fp
.node
.pat
)?
; // see (*2)
1193 let cmt_field
= self.cat_field(pat
, cmt
.clone(), fp
.node
.name
, field_ty
);
1194 self.cat_pattern_(cmt_field
, &fp
.node
.pat
, op
)?
;
1198 PatKind
::Binding(.., Some(ref subpat
)) => {
1199 self.cat_pattern_(cmt
, &subpat
, op
)?
;
1202 PatKind
::Tuple(ref subpats
, ddpos
) => {
1204 let expected_len
= match self.pat_ty(&pat
)?
.sty
{
1205 ty
::TyTuple(ref tys
, _
) => tys
.len(),
1206 ref ty
=> span_bug
!(pat
.span
, "tuple pattern unexpected type {:?}", ty
),
1208 for (i
, subpat
) in subpats
.iter().enumerate_and_adjust(expected_len
, ddpos
) {
1209 let subpat_ty
= self.pat_ty(&subpat
)?
; // see (*2)
1210 let subcmt
= self.cat_imm_interior(pat
, cmt
.clone(), subpat_ty
,
1211 InteriorField(PositionalField(i
)));
1212 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1216 PatKind
::Box(ref subpat
) | PatKind
::Ref(ref subpat
, _
) => {
1217 // box p1, &p1, &mut p1. we can ignore the mutability of
1218 // PatKind::Ref since that information is already contained
1220 let subcmt
= self.cat_deref(pat
, cmt
, 0)?
;
1221 self.cat_pattern_(subcmt
, &subpat
, op
)?
;
1224 PatKind
::Slice(ref before
, ref slice
, ref after
) => {
1225 let context
= InteriorOffsetKind
::Pattern
;
1226 let elt_cmt
= self.cat_index(pat
, cmt
, context
)?
;
1227 for before_pat
in before
{
1228 self.cat_pattern_(elt_cmt
.clone(), &before_pat
, op
)?
;
1230 if let Some(ref slice_pat
) = *slice
{
1231 self.cat_pattern_(elt_cmt
.clone(), &slice_pat
, op
)?
;
1233 for after_pat
in after
{
1234 self.cat_pattern_(elt_cmt
.clone(), &after_pat
, op
)?
;
1238 PatKind
::Path(_
) | PatKind
::Binding(.., None
) |
1239 PatKind
::Lit(..) | PatKind
::Range(..) | PatKind
::Wild
=> {
1247 fn overloaded_method_return_ty(&self,
1248 method_ty
: Ty
<'tcx
>)
1251 // When we process an overloaded `*` or `[]` etc, we often
1252 // need to extract the return type of the method. These method
1253 // types are generated by method resolution and always have
1254 // all late-bound regions fully instantiated, so we just want
1255 // to skip past the binder.
1256 self.tcx().no_late_bound_regions(&method_ty
.fn_ret())
1261 #[derive(Clone, Debug)]
1262 pub enum Aliasability
{
1263 FreelyAliasable(AliasableReason
),
1265 ImmutableUnique(Box
<Aliasability
>),
1268 #[derive(Copy, Clone, Debug)]
1269 pub enum AliasableReason
{
1271 AliasableClosure(ast
::NodeId
), // Aliasable due to capture Fn closure env
1273 UnaliasableImmutable
, // Created as needed upon seeing ImmutableUnique
1278 impl<'tcx
> cmt_
<'tcx
> {
1279 pub fn guarantor(&self) -> cmt
<'tcx
> {
1280 //! Returns `self` after stripping away any derefs or
1281 //! interior content. The return value is basically the `cmt` which
1282 //! determines how long the value in `self` remains live.
1285 Categorization
::Rvalue(..) |
1286 Categorization
::StaticItem
|
1287 Categorization
::Local(..) |
1288 Categorization
::Deref(.., UnsafePtr(..)) |
1289 Categorization
::Deref(.., BorrowedPtr(..)) |
1290 Categorization
::Deref(.., Implicit(..)) |
1291 Categorization
::Upvar(..) => {
1292 Rc
::new((*self).clone())
1294 Categorization
::Downcast(ref b
, _
) |
1295 Categorization
::Interior(ref b
, _
) |
1296 Categorization
::Deref(ref b
, _
, Unique
) => {
1302 /// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
1303 pub fn freely_aliasable(&self) -> Aliasability
{
1304 // Maybe non-obvious: copied upvars can only be considered
1305 // non-aliasable in once closures, since any other kind can be
1306 // aliased and eventually recused.
1309 Categorization
::Deref(ref b
, _
, BorrowedPtr(ty
::MutBorrow
, _
)) |
1310 Categorization
::Deref(ref b
, _
, Implicit(ty
::MutBorrow
, _
)) |
1311 Categorization
::Deref(ref b
, _
, BorrowedPtr(ty
::UniqueImmBorrow
, _
)) |
1312 Categorization
::Deref(ref b
, _
, Implicit(ty
::UniqueImmBorrow
, _
)) |
1313 Categorization
::Downcast(ref b
, _
) |
1314 Categorization
::Interior(ref b
, _
) => {
1315 // Aliasability depends on base cmt
1316 b
.freely_aliasable()
1319 Categorization
::Deref(ref b
, _
, Unique
) => {
1320 let sub
= b
.freely_aliasable();
1321 if b
.mutbl
.is_mutable() {
1322 // Aliasability depends on base cmt alone
1325 // Do not allow mutation through an immutable box.
1326 ImmutableUnique(Box
::new(sub
))
1330 Categorization
::Rvalue(..) |
1331 Categorization
::Local(..) |
1332 Categorization
::Upvar(..) |
1333 Categorization
::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but...
1337 Categorization
::StaticItem
=> {
1338 if self.mutbl
.is_mutable() {
1339 FreelyAliasable(AliasableStaticMut
)
1341 FreelyAliasable(AliasableStatic
)
1345 Categorization
::Deref(ref base
, _
, BorrowedPtr(ty
::ImmBorrow
, _
)) |
1346 Categorization
::Deref(ref base
, _
, Implicit(ty
::ImmBorrow
, _
)) => {
1348 Categorization
::Upvar(Upvar{ id, .. }
) =>
1349 FreelyAliasable(AliasableClosure(id
.closure_expr_id
)),
1350 _
=> FreelyAliasable(AliasableBorrowed
)
1356 // Digs down through one or two layers of deref and grabs the cmt
1357 // for the upvar if a note indicates there is one.
1358 pub fn upvar(&self) -> Option
<cmt
<'tcx
>> {
1360 NoteClosureEnv(..) | NoteUpvarRef(..) => {
1361 Some(match self.cat
{
1362 Categorization
::Deref(ref inner
, ..) => {
1364 Categorization
::Deref(ref inner
, ..) => inner
.clone(),
1365 Categorization
::Upvar(..) => inner
.clone(),
1377 pub fn descriptive_string(&self, tcx
: TyCtxt
) -> String
{
1379 Categorization
::StaticItem
=> {
1380 "static item".to_string()
1382 Categorization
::Rvalue(..) => {
1383 "non-lvalue".to_string()
1385 Categorization
::Local(vid
) => {
1386 if tcx
.hir
.is_argument(vid
) {
1387 "argument".to_string()
1389 "local variable".to_string()
1392 Categorization
::Deref(.., pk
) => {
1393 let upvar
= self.upvar();
1394 match upvar
.as_ref().map(|i
| &i
.cat
) {
1395 Some(&Categorization
::Upvar(ref var
)) => {
1402 format
!("indexed content")
1405 format
!("`Box` content")
1408 format
!("dereference of raw pointer")
1410 BorrowedPtr(..) => {
1411 format
!("borrowed content")
1417 Categorization
::Interior(_
, InteriorField(NamedField(_
))) => {
1420 Categorization
::Interior(_
, InteriorField(PositionalField(_
))) => {
1421 "anonymous field".to_string()
1423 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1425 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1427 "indexed content".to_string()
1429 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1431 Categorization
::Interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1433 "pattern-bound indexed content".to_string()
1435 Categorization
::Upvar(ref var
) => {
1438 Categorization
::Downcast(ref cmt
, _
) => {
1439 cmt
.descriptive_string(tcx
)
1445 impl<'tcx
> fmt
::Debug
for cmt_
<'tcx
> {
1446 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1447 write
!(f
, "{{{:?} id:{} m:{:?} ty:{:?}}}",
1455 impl<'tcx
> fmt
::Debug
for Categorization
<'tcx
> {
1456 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1458 Categorization
::StaticItem
=> write
!(f
, "static"),
1459 Categorization
::Rvalue(r
, or
) => {
1460 write
!(f
, "rvalue({:?}, {:?})", r
, or
)
1462 Categorization
::Local(id
) => {
1463 let name
= ty
::tls
::with(|tcx
| tcx
.local_var_name_str(id
));
1464 write
!(f
, "local({})", name
)
1466 Categorization
::Upvar(upvar
) => {
1467 write
!(f
, "upvar({:?})", upvar
)
1469 Categorization
::Deref(ref cmt
, derefs
, ptr
) => {
1470 write
!(f
, "{:?}-{:?}{}->", cmt
.cat
, ptr
, derefs
)
1472 Categorization
::Interior(ref cmt
, interior
) => {
1473 write
!(f
, "{:?}.{:?}", cmt
.cat
, interior
)
1475 Categorization
::Downcast(ref cmt
, _
) => {
1476 write
!(f
, "{:?}->(enum)", cmt
.cat
)
1482 pub fn ptr_sigil(ptr
: PointerKind
) -> &'
static str {
1485 BorrowedPtr(ty
::ImmBorrow
, _
) |
1486 Implicit(ty
::ImmBorrow
, _
) => "&",
1487 BorrowedPtr(ty
::MutBorrow
, _
) |
1488 Implicit(ty
::MutBorrow
, _
) => "&mut",
1489 BorrowedPtr(ty
::UniqueImmBorrow
, _
) |
1490 Implicit(ty
::UniqueImmBorrow
, _
) => "&unique",
1491 UnsafePtr(_
) => "*",
1495 impl<'tcx
> fmt
::Debug
for PointerKind
<'tcx
> {
1496 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1498 Unique
=> write
!(f
, "Box"),
1499 BorrowedPtr(ty
::ImmBorrow
, ref r
) |
1500 Implicit(ty
::ImmBorrow
, ref r
) => {
1501 write
!(f
, "&{:?}", r
)
1503 BorrowedPtr(ty
::MutBorrow
, ref r
) |
1504 Implicit(ty
::MutBorrow
, ref r
) => {
1505 write
!(f
, "&{:?} mut", r
)
1507 BorrowedPtr(ty
::UniqueImmBorrow
, ref r
) |
1508 Implicit(ty
::UniqueImmBorrow
, ref r
) => {
1509 write
!(f
, "&{:?} uniq", r
)
1511 UnsafePtr(_
) => write
!(f
, "*")
1516 impl fmt
::Debug
for InteriorKind
{
1517 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1519 InteriorField(NamedField(fld
)) => write
!(f
, "{}", fld
),
1520 InteriorField(PositionalField(i
)) => write
!(f
, "#{}", i
),
1521 InteriorElement(..) => write
!(f
, "[]"),
1526 impl fmt
::Debug
for Upvar
{
1527 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1528 write
!(f
, "{:?}/{:?}", self.id
, self.kind
)
1532 impl fmt
::Display
for Upvar
{
1533 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
1534 let kind
= match self.kind
{
1535 ty
::ClosureKind
::Fn
=> "Fn",
1536 ty
::ClosureKind
::FnMut
=> "FnMut",
1537 ty
::ClosureKind
::FnOnce
=> "FnOnce",
1539 write
!(f
, "captured outer variable in an `{}` closure", kind
)