1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 //! The job of the categorization module is to analyze an expression to
14 //! determine what kind of memory is used in evaluating it (for example,
15 //! where dereferences occur and what kind of pointer is dereferenced;
16 //! whether the memory is mutable; etc)
18 //! Categorization effectively transforms all of our expressions into
19 //! expressions of the following forms (the actual enum has many more
20 //! possibilities, naturally, but they are all variants of these base
23 //! E = rvalue // some computed rvalue
24 //! | x // address of a local variable or argument
25 //! | *E // deref of a ptr
26 //! | E.comp // access to an interior component
28 //! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
29 //! address where the result is to be found. If Expr is an lvalue, then this
30 //! is the address of the lvalue. If Expr is an rvalue, this is the address of
31 //! some temporary spot in memory where the result is stored.
33 //! Now, cat_expr() classifies the expression Expr and the address A=ToAddr(Expr)
36 //! - cat: what kind of expression was this? This is a subset of the
37 //! full expression forms which only includes those that we care about
38 //! for the purpose of the analysis.
39 //! - mutbl: mutability of the address A
40 //! - ty: the type of data found at the address A
42 //! The resulting categorization tree differs somewhat from the expressions
43 //! themselves. For example, auto-derefs are explicit. Also, an index a[b] is
44 //! decomposed into two operations: a dereference to reach the array data and
45 //! then an index to jump forward to the relevant item.
47 //! ## By-reference upvars
49 //! One part of the translation which may be non-obvious is that we translate
50 //! closure upvars into the dereference of a borrowed pointer; this more closely
51 //! resembles the runtime translation. So, for example, if we had:
55 //! let inc = || x += y;
57 //! Then when we categorize `x` (*within* the closure) we would yield a
58 //! result of `*x'`, effectively, where `x'` is a `cat_upvar` reference
59 //! tied to `x`. The type of `x'` will be a borrowed pointer.
61 #![allow(non_camel_case_types)]
63 pub use self::PointerKind
::*;
64 pub use self::InteriorKind
::*;
65 pub use self::FieldName
::*;
66 pub use self::ElementKind
::*;
67 pub use self::MutabilityCategory
::*;
68 pub use self::InteriorSafety
::*;
69 pub use self::AliasableReason
::*;
70 pub use self::Note
::*;
71 pub use self::deref_kind
::*;
72 pub use self::categorization
::*;
74 use self::Aliasability
::*;
76 use middle
::check_const
;
79 use middle
::ty
::{self, Ty}
;
80 use util
::nodemap
::NodeMap
;
81 use util
::ppaux
::{Repr, UserString}
;
83 use syntax
::ast
::{MutImmutable, MutMutable}
;
86 use syntax
::codemap
::Span
;
87 use syntax
::print
::pprust
;
88 use syntax
::parse
::token
;
90 use std
::cell
::RefCell
;
93 #[derive(Clone, PartialEq, Debug)]
94 pub enum categorization
<'tcx
> {
95 cat_rvalue(ty
::Region
), // temporary val, argument is its scope
97 cat_upvar(Upvar
), // upvar referenced by closure env
98 cat_local(ast
::NodeId
), // local variable
99 cat_deref(cmt
<'tcx
>, usize, PointerKind
), // deref of a ptr
100 cat_interior(cmt
<'tcx
>, InteriorKind
), // something interior: field, tuple, etc
101 cat_downcast(cmt
<'tcx
>, ast
::DefId
), // selects a particular enum variant (*1)
103 // (*1) downcast is only required if the enum has more than one variant
106 // Represents any kind of upvar
107 #[derive(Clone, Copy, PartialEq, Debug)]
110 pub kind
: ty
::ClosureKind
113 // different kinds of pointers:
114 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
115 pub enum PointerKind
{
120 BorrowedPtr(ty
::BorrowKind
, ty
::Region
),
123 UnsafePtr(ast
::Mutability
),
125 /// Implicit deref of the `&T` that results from an overloaded index `[]`.
126 Implicit(ty
::BorrowKind
, ty
::Region
),
129 // We use the term "interior" to mean "something reachable from the
130 // base without a pointer dereference", e.g. a field
131 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
132 pub enum InteriorKind
{
133 InteriorField(FieldName
),
134 InteriorElement(InteriorOffsetKind
, ElementKind
),
137 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
139 NamedField(ast
::Name
),
140 PositionalField(usize)
143 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
144 pub enum InteriorOffsetKind
{
145 Index
, // e.g. `array_expr[index_expr]`
146 Pattern
, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
149 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
150 pub enum ElementKind
{
155 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
156 pub enum MutabilityCategory
{
157 McImmutable
, // Immutable.
158 McDeclared
, // Directly declared as mutable.
159 McInherited
, // Inherited from the fact that owner is mutable.
162 // A note about the provenance of a `cmt`. This is used for
163 // special-case handling of upvars such as mutability inference.
164 // Upvar categorization can generate a variable number of nested
165 // derefs. The note allows detecting them without deep pattern
166 // matching on the categorization.
167 #[derive(Clone, Copy, PartialEq, Debug)]
169 NoteClosureEnv(ty
::UpvarId
), // Deref through closure env
170 NoteUpvarRef(ty
::UpvarId
), // Deref through by-ref upvar
171 NoteNone
// Nothing special
174 // `cmt`: "Category, Mutability, and Type".
176 // a complete categorization of a value indicating where it originated
177 // and how it is located, as well as the mutability of the memory in
178 // which the value is stored.
180 // *WARNING* The field `cmt.type` is NOT necessarily the same as the
181 // result of `node_id_to_type(cmt.id)`. This is because the `id` is
182 // always the `id` of the node producing the type; in an expression
183 // like `*x`, the type of this deref node is the deref'd type (`T`),
184 // but in a pattern like `@x`, the `@x` pattern is again a
185 // dereference, but its type is the type *before* the dereference
186 // (`@T`). So use `cmt.ty` to find the type of the value in a consistent
187 // fashion. For more details, see the method `cat_pattern`
188 #[derive(Clone, PartialEq, Debug)]
189 pub struct cmt_
<'tcx
> {
190 pub id
: ast
::NodeId
, // id of expr/pat producing this value
191 pub span
: Span
, // span of same expr/pat
192 pub cat
: categorization
<'tcx
>, // categorization of expr
193 pub mutbl
: MutabilityCategory
, // mutability of expr as lvalue
194 pub ty
: Ty
<'tcx
>, // type of the expr (*see WARNING above*)
195 pub note
: Note
, // Note about the provenance of this cmt
198 pub type cmt
<'tcx
> = Rc
<cmt_
<'tcx
>>;
200 // We pun on *T to mean both actual deref of a ptr as well
201 // as accessing of components:
202 #[derive(Copy, Clone)]
203 pub enum deref_kind
{
204 deref_ptr(PointerKind
),
205 deref_interior(InteriorKind
),
208 type DerefKindContext
= Option
<InteriorOffsetKind
>;
210 // Categorizes a derefable type. Note that we include vectors and strings as
211 // derefable (we model an index as the combination of a deref and then a
212 // pointer adjustment).
213 fn deref_kind(t
: Ty
, context
: DerefKindContext
) -> McResult
<deref_kind
> {
216 Ok(deref_ptr(Unique
))
219 ty
::ty_rptr(r
, mt
) => {
220 let kind
= ty
::BorrowKind
::from_mutbl(mt
.mutbl
);
221 Ok(deref_ptr(BorrowedPtr(kind
, *r
)))
224 ty
::ty_ptr(ref mt
) => {
225 Ok(deref_ptr(UnsafePtr(mt
.mutbl
)))
229 ty
::ty_struct(..) => { // newtype
230 Ok(deref_interior(InteriorField(PositionalField(0))))
233 ty
::ty_vec(_
, _
) | ty
::ty_str
=> {
234 // no deref of indexed content without supplying InteriorOffsetKind
235 if let Some(context
) = context
{
236 Ok(deref_interior(InteriorElement(context
, element_kind(t
))))
247 fn id(&self) -> ast
::NodeId
;
248 fn span(&self) -> Span
;
251 impl ast_node
for ast
::Expr
{
252 fn id(&self) -> ast
::NodeId { self.id }
253 fn span(&self) -> Span { self.span }
256 impl ast_node
for ast
::Pat
{
257 fn id(&self) -> ast
::NodeId { self.id }
258 fn span(&self) -> Span { self.span }
261 pub struct MemCategorizationContext
<'t
,TYPER
:'t
> {
265 impl<'t
,TYPER
:'t
> Copy
for MemCategorizationContext
<'t
,TYPER
> {}
266 impl<'t
,TYPER
:'t
> Clone
for MemCategorizationContext
<'t
,TYPER
> {
267 fn clone(&self) -> MemCategorizationContext
<'t
,TYPER
> { *self }
270 pub type McResult
<T
> = Result
<T
, ()>;
272 /// The `Typer` trait provides the interface for the mem-categorization
273 /// module to the results of the type check. It can be used to query
274 /// the type assigned to an expression node, to inquire after adjustments,
277 /// This interface is needed because mem-categorization is used from
278 /// two places: `regionck` and `borrowck`. `regionck` executes before
279 /// type inference is complete, and hence derives types and so on from
280 /// intermediate tables. This also implies that type errors can occur,
281 /// and hence `node_ty()` and friends return a `Result` type -- any
282 /// error will propagate back up through the mem-categorization
285 /// In the borrow checker, in contrast, type checking is complete and we
286 /// know that no errors have occurred, so we simply consult the tcx and we
287 /// can be sure that only `Ok` results will occur.
288 pub trait Typer
<'tcx
> : ty
::ClosureTyper
<'tcx
> {
289 fn node_ty(&self, id
: ast
::NodeId
) -> McResult
<Ty
<'tcx
>>;
290 fn expr_ty_adjusted(&self, expr
: &ast
::Expr
) -> McResult
<Ty
<'tcx
>>;
291 fn type_moves_by_default(&self, span
: Span
, ty
: Ty
<'tcx
>) -> bool
;
292 fn node_method_ty(&self, method_call
: ty
::MethodCall
) -> Option
<Ty
<'tcx
>>;
293 fn node_method_origin(&self, method_call
: ty
::MethodCall
)
294 -> Option
<ty
::MethodOrigin
<'tcx
>>;
295 fn adjustments
<'a
>(&'a
self) -> &'a RefCell
<NodeMap
<ty
::AutoAdjustment
<'tcx
>>>;
296 fn is_method_call(&self, id
: ast
::NodeId
) -> bool
;
297 fn temporary_scope(&self, rvalue_id
: ast
::NodeId
) -> Option
<region
::CodeExtent
>;
298 fn upvar_capture(&self, upvar_id
: ty
::UpvarId
) -> Option
<ty
::UpvarCapture
>;
301 impl MutabilityCategory
{
302 pub fn from_mutbl(m
: ast
::Mutability
) -> MutabilityCategory
{
304 MutImmutable
=> McImmutable
,
305 MutMutable
=> McDeclared
307 debug
!("MutabilityCategory::{}({:?}) => {:?}",
308 "from_mutbl", m
, ret
);
312 pub fn from_borrow_kind(borrow_kind
: ty
::BorrowKind
) -> MutabilityCategory
{
313 let ret
= match borrow_kind
{
314 ty
::ImmBorrow
=> McImmutable
,
315 ty
::UniqueImmBorrow
=> McImmutable
,
316 ty
::MutBorrow
=> McDeclared
,
318 debug
!("MutabilityCategory::{}({:?}) => {:?}",
319 "from_borrow_kind", borrow_kind
, ret
);
323 fn from_pointer_kind(base_mutbl
: MutabilityCategory
,
324 ptr
: PointerKind
) -> MutabilityCategory
{
325 let ret
= match ptr
{
329 BorrowedPtr(borrow_kind
, _
) | Implicit(borrow_kind
, _
) => {
330 MutabilityCategory
::from_borrow_kind(borrow_kind
)
333 MutabilityCategory
::from_mutbl(m
)
336 debug
!("MutabilityCategory::{}({:?}, {:?}) => {:?}",
337 "from_pointer_kind", base_mutbl
, ptr
, ret
);
341 fn from_local(tcx
: &ty
::ctxt
, id
: ast
::NodeId
) -> MutabilityCategory
{
342 let ret
= match tcx
.map
.get(id
) {
343 ast_map
::NodeLocal(p
) | ast_map
::NodeArg(p
) => match p
.node
{
344 ast
::PatIdent(bind_mode
, _
, _
) => {
345 if bind_mode
== ast
::BindByValue(ast
::MutMutable
) {
351 _
=> tcx
.sess
.span_bug(p
.span
, "expected identifier pattern")
353 _
=> tcx
.sess
.span_bug(tcx
.map
.span(id
), "expected identifier pattern")
355 debug
!("MutabilityCategory::{}(tcx, id={:?}) => {:?}",
356 "from_local", id
, ret
);
360 pub fn inherit(&self) -> MutabilityCategory
{
361 let ret
= match *self {
362 McImmutable
=> McImmutable
,
363 McDeclared
=> McInherited
,
364 McInherited
=> McInherited
,
366 debug
!("{:?}.inherit() => {:?}", self, ret
);
370 pub fn is_mutable(&self) -> bool
{
371 let ret
= match *self {
372 McImmutable
=> false,
376 debug
!("{:?}.is_mutable() => {:?}", self, ret
);
380 pub fn is_immutable(&self) -> bool
{
381 let ret
= match *self {
383 McDeclared
| McInherited
=> false
385 debug
!("{:?}.is_immutable() => {:?}", self, ret
);
389 pub fn to_user_str(&self) -> &'
static str {
391 McDeclared
| McInherited
=> "mutable",
392 McImmutable
=> "immutable",
397 impl<'t
,'tcx
,TYPER
:Typer
<'tcx
>> MemCategorizationContext
<'t
,TYPER
> {
398 pub fn new(typer
: &'t TYPER
) -> MemCategorizationContext
<'t
,TYPER
> {
399 MemCategorizationContext { typer: typer }
402 fn tcx(&self) -> &'t ty
::ctxt
<'tcx
> {
406 fn expr_ty(&self, expr
: &ast
::Expr
) -> McResult
<Ty
<'tcx
>> {
407 self.typer
.node_ty(expr
.id
)
410 fn expr_ty_adjusted(&self, expr
: &ast
::Expr
) -> McResult
<Ty
<'tcx
>> {
411 let unadjusted_ty
= try
!(self.expr_ty(expr
));
412 Ok(ty
::adjust_ty(self.tcx(), expr
.span
, expr
.id
, unadjusted_ty
,
413 self.typer
.adjustments().borrow().get(&expr
.id
),
414 |method_call
| self.typer
.node_method_ty(method_call
)))
417 fn node_ty(&self, id
: ast
::NodeId
) -> McResult
<Ty
<'tcx
>> {
418 self.typer
.node_ty(id
)
421 fn pat_ty(&self, pat
: &ast
::Pat
) -> McResult
<Ty
<'tcx
>> {
422 let tcx
= self.typer
.tcx();
423 let base_ty
= try
!(self.typer
.node_ty(pat
.id
));
424 // FIXME (Issue #18207): This code detects whether we are
425 // looking at a `ref x`, and if so, figures out what the type
426 // *being borrowed* is. But ideally we would put in a more
427 // fundamental fix to this conflated use of the node id.
428 let ret_ty
= match pat
.node
{
429 ast
::PatIdent(ast
::BindByRef(_
), _
, _
) => {
430 // a bind-by-ref means that the base_ty will be the type of the ident itself,
431 // but what we want here is the type of the underlying value being borrowed.
432 // So peel off one-level, turning the &T into T.
433 match ty
::deref(base_ty
, false) {
435 None
=> { return Err(()); }
440 debug
!("pat_ty(pat={}) base_ty={} ret_ty={}",
441 pat
.repr(tcx
), base_ty
.repr(tcx
), ret_ty
.repr(tcx
));
445 pub fn cat_expr(&self, expr
: &ast
::Expr
) -> McResult
<cmt
<'tcx
>> {
446 match self.typer
.adjustments().borrow().get(&expr
.id
) {
449 self.cat_expr_unadjusted(expr
)
452 Some(adjustment
) => {
456 autoref
: None
, unsize
: None
, autoderefs
, ..}) => {
457 // Equivalent to *expr or something similar.
458 self.cat_expr_autoderefd(expr
, autoderefs
)
461 ty
::AdjustReifyFnPointer
|
462 ty
::AdjustUnsafeFnPointer
|
463 ty
::AdjustDerefRef(_
) => {
464 debug
!("cat_expr({}): {}",
465 adjustment
.repr(self.tcx()),
466 expr
.repr(self.tcx()));
467 // Result is an rvalue.
468 let expr_ty
= try
!(self.expr_ty_adjusted(expr
));
469 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
476 pub fn cat_expr_autoderefd(&self,
479 -> McResult
<cmt
<'tcx
>> {
480 let mut cmt
= try
!(self.cat_expr_unadjusted(expr
));
481 debug
!("cat_expr_autoderefd: autoderefs={}, cmt={}",
483 cmt
.repr(self.tcx()));
484 for deref
in 1..autoderefs
+ 1 {
485 cmt
= try
!(self.cat_deref(expr
, cmt
, deref
, None
));
490 pub fn cat_expr_unadjusted(&self, expr
: &ast
::Expr
) -> McResult
<cmt
<'tcx
>> {
491 debug
!("cat_expr: id={} expr={}", expr
.id
, expr
.repr(self.tcx()));
493 let expr_ty
= try
!(self.expr_ty(expr
));
495 ast
::ExprUnary(ast
::UnDeref
, ref e_base
) => {
496 let base_cmt
= try
!(self.cat_expr(&**e_base
));
497 self.cat_deref(expr
, base_cmt
, 0, None
)
500 ast
::ExprField(ref base
, f_name
) => {
501 let base_cmt
= try
!(self.cat_expr(&**base
));
502 debug
!("cat_expr(cat_field): id={} expr={} base={}",
504 expr
.repr(self.tcx()),
505 base_cmt
.repr(self.tcx()));
506 Ok(self.cat_field(expr
, base_cmt
, f_name
.node
.name
, expr_ty
))
509 ast
::ExprTupField(ref base
, idx
) => {
510 let base_cmt
= try
!(self.cat_expr(&**base
));
511 Ok(self.cat_tup_field(expr
, base_cmt
, idx
.node
, expr_ty
))
514 ast
::ExprIndex(ref base
, _
) => {
515 let method_call
= ty
::MethodCall
::expr(expr
.id());
516 let context
= InteriorOffsetKind
::Index
;
517 match self.typer
.node_method_ty(method_call
) {
519 // If this is an index implemented by a method call, then it
520 // will include an implicit deref of the result.
521 let ret_ty
= self.overloaded_method_return_ty(method_ty
);
523 // The index method always returns an `&T`, so
524 // dereference it to find the result type.
525 let elem_ty
= match ret_ty
.sty
{
526 ty
::ty_rptr(_
, mt
) => mt
.ty
,
528 debug
!("cat_expr_unadjusted: return type of overloaded index is {}?",
529 ret_ty
.repr(self.tcx()));
534 // The call to index() returns a `&T` value, which
535 // is an rvalue. That is what we will be
537 let base_cmt
= self.cat_rvalue_node(expr
.id(), expr
.span(), ret_ty
);
538 self.cat_deref_common(expr
, base_cmt
, 1, elem_ty
, Some(context
), true)
541 self.cat_index(expr
, try
!(self.cat_expr(&**base
)), context
)
546 ast
::ExprPath(..) => {
547 let def
= self.tcx().def_map
.borrow().get(&expr
.id
).unwrap().full_def();
548 self.cat_def(expr
.id
, expr
.span
, expr_ty
, def
)
551 ast
::ExprParen(ref e
) => {
555 ast
::ExprAddrOf(..) | ast
::ExprCall(..) |
556 ast
::ExprAssign(..) | ast
::ExprAssignOp(..) |
557 ast
::ExprClosure(..) | ast
::ExprRet(..) |
558 ast
::ExprUnary(..) | ast
::ExprRange(..) |
559 ast
::ExprMethodCall(..) | ast
::ExprCast(..) |
560 ast
::ExprVec(..) | ast
::ExprTup(..) | ast
::ExprIf(..) |
561 ast
::ExprBinary(..) | ast
::ExprWhile(..) |
562 ast
::ExprBlock(..) | ast
::ExprLoop(..) | ast
::ExprMatch(..) |
563 ast
::ExprLit(..) | ast
::ExprBreak(..) | ast
::ExprMac(..) |
564 ast
::ExprAgain(..) | ast
::ExprStruct(..) | ast
::ExprRepeat(..) |
565 ast
::ExprInlineAsm(..) | ast
::ExprBox(..) => {
566 Ok(self.cat_rvalue_node(expr
.id(), expr
.span(), expr_ty
))
569 ast
::ExprIfLet(..) => {
570 self.tcx().sess
.span_bug(expr
.span
, "non-desugared ExprIfLet");
572 ast
::ExprWhileLet(..) => {
573 self.tcx().sess
.span_bug(expr
.span
, "non-desugared ExprWhileLet");
575 ast
::ExprForLoop(..) => {
576 self.tcx().sess
.span_bug(expr
.span
, "non-desugared ExprForLoop");
581 pub fn cat_def(&self,
586 -> McResult
<cmt
<'tcx
>> {
587 debug
!("cat_def: id={} expr={} def={:?}",
588 id
, expr_ty
.repr(self.tcx()), def
);
591 def
::DefStruct(..) | def
::DefVariant(..) | def
::DefConst(..) |
592 def
::DefAssociatedConst(..) | def
::DefFn(..) | def
::DefMethod(..) => {
593 Ok(self.cat_rvalue_node(id
, span
, expr_ty
))
595 def
::DefMod(_
) | def
::DefForeignMod(_
) | def
::DefUse(_
) |
596 def
::DefTrait(_
) | def
::DefTy(..) | def
::DefPrimTy(_
) |
597 def
::DefTyParam(..) | def
::DefRegion(_
) |
598 def
::DefLabel(_
) | def
::DefSelfTy(..) |
599 def
::DefAssociatedTy(..) => {
610 def
::DefStatic(_
, mutbl
) => {
615 mutbl
: if mutbl { McDeclared }
else { McImmutable}
,
621 def
::DefUpvar(var_id
, fn_node_id
) => {
622 let ty
= try
!(self.node_ty(fn_node_id
));
624 ty
::ty_closure(closure_id
, _
) => {
625 match self.typer
.closure_kind(closure_id
) {
627 self.cat_upvar(id
, span
, var_id
, fn_node_id
, kind
)
630 self.tcx().sess
.span_bug(
632 &*format
!("No closure kind for {:?}", closure_id
));
637 self.tcx().sess
.span_bug(
639 &format
!("Upvar of non-closure {} - {}",
641 ty
.repr(self.tcx())));
646 def
::DefLocal(vid
) => {
651 mutbl
: MutabilityCategory
::from_local(self.tcx(), vid
),
659 // Categorize an upvar, complete with invisible derefs of closure
660 // environment and upvar reference as appropriate.
665 fn_node_id
: ast
::NodeId
,
666 kind
: ty
::ClosureKind
)
667 -> McResult
<cmt
<'tcx
>>
669 // An upvar can have up to 3 components. We translate first to a
670 // `cat_upvar`, which is itself a fiction -- it represents the reference to the
671 // field from the environment.
673 // `cat_upvar`. Next, we add a deref through the implicit
674 // environment pointer with an anonymous free region 'env and
675 // appropriate borrow kind for closure kinds that take self by
676 // reference. Finally, if the upvar was captured
677 // by-reference, we add a deref through that reference. The
678 // region of this reference is an inference variable 'up that
679 // was previously generated and recorded in the upvar borrow
680 // map. The borrow kind bk is inferred by based on how the
683 // This results in the following table for concrete closure
687 // ---------------+----------------------+-------------------------------
688 // Fn | copied -> &'env | upvar -> &'env -> &'up bk
689 // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
690 // FnOnce | copied | upvar -> &'up bk
692 let upvar_id
= ty
::UpvarId
{ var_id
: var_id
,
693 closure_expr_id
: fn_node_id
};
694 let var_ty
= try
!(self.node_ty(var_id
));
696 // Mutability of original variable itself
697 let var_mutbl
= MutabilityCategory
::from_local(self.tcx(), var_id
);
699 // Construct the upvar. This represents access to the field
700 // from the environment (perhaps we should eventually desugar
701 // this field further, but it will do for now).
702 let cmt_result
= cmt_
{
705 cat
: cat_upvar(Upvar {id: upvar_id, kind: kind}
),
711 // If this is a `FnMut` or `Fn` closure, then the above is
712 // conceptually a `&mut` or `&` reference, so we have to add a
714 let cmt_result
= match kind
{
715 ty
::FnOnceClosureKind
=> {
718 ty
::FnMutClosureKind
=> {
719 self.env_deref(id
, span
, upvar_id
, var_mutbl
, ty
::MutBorrow
, cmt_result
)
721 ty
::FnClosureKind
=> {
722 self.env_deref(id
, span
, upvar_id
, var_mutbl
, ty
::ImmBorrow
, cmt_result
)
726 // If this is a by-ref capture, then the upvar we loaded is
727 // actually a reference, so we have to add an implicit deref
729 let upvar_id
= ty
::UpvarId
{ var_id
: var_id
,
730 closure_expr_id
: fn_node_id
};
731 let upvar_capture
= self.typer
.upvar_capture(upvar_id
).unwrap();
732 let cmt_result
= match upvar_capture
{
733 ty
::UpvarCapture
::ByValue
=> {
736 ty
::UpvarCapture
::ByRef(upvar_borrow
) => {
737 let ptr
= BorrowedPtr(upvar_borrow
.kind
, upvar_borrow
.region
);
741 cat
: cat_deref(Rc
::new(cmt_result
), 0, ptr
),
742 mutbl
: MutabilityCategory
::from_borrow_kind(upvar_borrow
.kind
),
744 note
: NoteUpvarRef(upvar_id
)
749 let ret
= Rc
::new(cmt_result
);
750 debug
!("cat_upvar ret={}", ret
.repr(self.tcx()));
757 upvar_id
: ty
::UpvarId
,
758 upvar_mutbl
: MutabilityCategory
,
759 env_borrow_kind
: ty
::BorrowKind
,
760 cmt_result
: cmt_
<'tcx
>)
763 // Look up the node ID of the closure body so we can construct
764 // a free region within it
766 let fn_expr
= match self.tcx().map
.find(upvar_id
.closure_expr_id
) {
767 Some(ast_map
::NodeExpr(e
)) => e
,
772 ast
::ExprClosure(_
, _
, ref body
) => body
.id
,
777 // Region of environment pointer
778 let env_region
= ty
::ReFree(ty
::FreeRegion
{
779 // The environment of a closure is guaranteed to
780 // outlive any bindings introduced in the body of the
782 scope
: region
::DestructionScopeData
::new(fn_body_id
),
783 bound_region
: ty
::BrEnv
786 let env_ptr
= BorrowedPtr(env_borrow_kind
, env_region
);
788 let var_ty
= cmt_result
.ty
;
790 // We need to add the env deref. This means
791 // that the above is actually immutable and
792 // has a ref type. However, nothing should
793 // actually look at the type, so we can get
794 // away with stuffing a `ty_err` in there
795 // instead of bothering to construct a proper
797 let cmt_result
= cmt_
{
799 ty
: self.tcx().types
.err
,
803 let mut deref_mutbl
= MutabilityCategory
::from_borrow_kind(env_borrow_kind
);
805 // Issue #18335. If variable is declared as immutable, override the
806 // mutability from the environment and substitute an `&T` anyway.
808 McImmutable
=> { deref_mutbl = McImmutable; }
809 McDeclared
| McInherited
=> { }
815 cat
: cat_deref(Rc
::new(cmt_result
), 0, env_ptr
),
818 note
: NoteClosureEnv(upvar_id
)
821 debug
!("env_deref ret {}", ret
.repr(self.tcx()));
826 /// Returns the lifetime of a temporary created by expr with id `id`.
827 /// This could be `'static` if `id` is part of a constant expression.
828 pub fn temporary_scope(&self, id
: ast
::NodeId
) -> ty
::Region
{
829 match self.typer
.temporary_scope(id
) {
830 Some(scope
) => ty
::ReScope(scope
),
835 pub fn cat_rvalue_node(&self,
840 let qualif
= self.tcx().const_qualif_map
.borrow().get(&id
).cloned()
841 .unwrap_or(check_const
::ConstQualif
::NOT_CONST
);
843 // Only promote `[T; 0]` before an RFC for rvalue promotions
845 let qualif
= match expr_ty
.sty
{
846 ty
::ty_vec(_
, Some(0)) => qualif
,
847 _
=> check_const
::ConstQualif
::NOT_CONST
850 // Compute maximum lifetime of this rvalue. This is 'static if
851 // we can promote to a constant, otherwise equal to enclosing temp
853 let re
= if qualif
.intersects(check_const
::ConstQualif
::NON_STATIC_BORROWS
) {
854 self.temporary_scope(id
)
858 let ret
= self.cat_rvalue(id
, span
, re
, expr_ty
);
859 debug
!("cat_rvalue_node ret {}", ret
.repr(self.tcx()));
863 pub fn cat_rvalue(&self,
866 temp_scope
: ty
::Region
,
867 expr_ty
: Ty
<'tcx
>) -> cmt
<'tcx
> {
868 let ret
= Rc
::new(cmt_
{
871 cat
:cat_rvalue(temp_scope
),
876 debug
!("cat_rvalue ret {}", ret
.repr(self.tcx()));
880 pub fn cat_field
<N
:ast_node
>(&self,
886 let ret
= Rc
::new(cmt_
{
889 mutbl
: base_cmt
.mutbl
.inherit(),
890 cat
: cat_interior(base_cmt
, InteriorField(NamedField(f_name
))),
894 debug
!("cat_field ret {}", ret
.repr(self.tcx()));
898 pub fn cat_tup_field
<N
:ast_node
>(&self,
904 let ret
= Rc
::new(cmt_
{
907 mutbl
: base_cmt
.mutbl
.inherit(),
908 cat
: cat_interior(base_cmt
, InteriorField(PositionalField(f_idx
))),
912 debug
!("cat_tup_field ret {}", ret
.repr(self.tcx()));
916 fn cat_deref
<N
:ast_node
>(&self,
920 deref_context
: DerefKindContext
)
921 -> McResult
<cmt
<'tcx
>> {
922 let method_call
= ty
::MethodCall
{
924 autoderef
: deref_cnt
as u32
926 let method_ty
= self.typer
.node_method_ty(method_call
);
928 debug
!("cat_deref: method_call={:?} method_ty={:?}",
929 method_call
, method_ty
.map(|ty
| ty
.repr(self.tcx())));
931 let base_cmt
= match method_ty
{
934 ty
::no_late_bound_regions(
935 self.tcx(), &ty
::ty_fn_ret(method_ty
)).unwrap().unwrap();
936 self.cat_rvalue_node(node
.id(), node
.span(), ref_ty
)
940 let base_cmt_ty
= base_cmt
.ty
;
941 match ty
::deref(base_cmt_ty
, true) {
943 let ret
= self.cat_deref_common(node
, base_cmt
, deref_cnt
,
946 /* implicit: */ false);
947 debug
!("cat_deref ret {}", ret
.repr(self.tcx()));
951 debug
!("Explicit deref of non-derefable type: {}",
952 base_cmt_ty
.repr(self.tcx()));
958 fn cat_deref_common
<N
:ast_node
>(&self,
963 deref_context
: DerefKindContext
,
965 -> McResult
<cmt
<'tcx
>>
967 let (m
, cat
) = match try
!(deref_kind(base_cmt
.ty
, deref_context
)) {
969 let ptr
= if implicit
{
971 BorrowedPtr(bk
, r
) => Implicit(bk
, r
),
972 _
=> self.tcx().sess
.span_bug(node
.span(),
973 "Implicit deref of non-borrowed pointer")
978 // for unique ptrs, we inherit mutability from the
980 (MutabilityCategory
::from_pointer_kind(base_cmt
.mutbl
, ptr
),
981 cat_deref(base_cmt
, deref_cnt
, ptr
))
983 deref_interior(interior
) => {
984 (base_cmt
.mutbl
.inherit(), cat_interior(base_cmt
, interior
))
987 let ret
= Rc
::new(cmt_
{
995 debug
!("cat_deref_common ret {}", ret
.repr(self.tcx()));
999 pub fn cat_index
<N
:ast_node
>(&self,
1001 mut base_cmt
: cmt
<'tcx
>,
1002 context
: InteriorOffsetKind
)
1003 -> McResult
<cmt
<'tcx
>> {
1004 //! Creates a cmt for an indexing operation (`[]`).
1006 //! One subtle aspect of indexing that may not be
1007 //! immediately obvious: for anything other than a fixed-length
1008 //! vector, an operation like `x[y]` actually consists of two
1009 //! disjoint (from the point of view of borrowck) operations.
1010 //! The first is a deref of `x` to create a pointer `p` that points
1011 //! at the first element in the array. The second operation is
1012 //! an index which adds `y*sizeof(T)` to `p` to obtain the
1013 //! pointer to `x[y]`. `cat_index` will produce a resulting
1014 //! cmt containing both this deref and the indexing,
1015 //! presuming that `base_cmt` is not of fixed-length type.
1018 //! - `elt`: the AST node being indexed
1019 //! - `base_cmt`: the cmt of `elt`
1021 let method_call
= ty
::MethodCall
::expr(elt
.id());
1022 let method_ty
= self.typer
.node_method_ty(method_call
);
1024 let element_ty
= match method_ty
{
1025 Some(method_ty
) => {
1026 let ref_ty
= self.overloaded_method_return_ty(method_ty
);
1027 base_cmt
= self.cat_rvalue_node(elt
.id(), elt
.span(), ref_ty
);
1029 // FIXME(#20649) -- why are we using the `self_ty` as the element type...?
1030 let self_ty
= ty
::ty_fn_sig(method_ty
).input(0);
1031 ty
::no_late_bound_regions(self.tcx(), &self_ty
).unwrap()
1034 match ty
::array_element_ty(self.tcx(), base_cmt
.ty
) {
1043 let m
= base_cmt
.mutbl
.inherit();
1044 let ret
= interior(elt
, base_cmt
.clone(), base_cmt
.ty
,
1045 m
, context
, element_ty
);
1046 debug
!("cat_index ret {}", ret
.repr(self.tcx()));
1049 fn interior
<'tcx
, N
: ast_node
>(elt
: &N
,
1052 mutbl
: MutabilityCategory
,
1053 context
: InteriorOffsetKind
,
1054 element_ty
: Ty
<'tcx
>) -> cmt
<'tcx
>
1056 let interior_elem
= InteriorElement(context
, element_kind(vec_ty
));
1060 cat
:cat_interior(of_cmt
, interior_elem
),
1068 // Takes either a vec or a reference to a vec and returns the cmt for the
1070 fn deref_vec
<N
:ast_node
>(&self,
1072 base_cmt
: cmt
<'tcx
>,
1073 context
: InteriorOffsetKind
)
1074 -> McResult
<cmt
<'tcx
>>
1076 let ret
= match try
!(deref_kind(base_cmt
.ty
, Some(context
))) {
1078 // for unique ptrs, we inherit mutability from the
1079 // owning reference.
1080 let m
= MutabilityCategory
::from_pointer_kind(base_cmt
.mutbl
, ptr
);
1082 // the deref is explicit in the resulting cmt
1086 cat
:cat_deref(base_cmt
.clone(), 0, ptr
),
1088 ty
: match ty
::deref(base_cmt
.ty
, false) {
1090 None
=> self.tcx().sess
.bug("Found non-derefable type")
1096 deref_interior(_
) => {
1100 debug
!("deref_vec ret {}", ret
.repr(self.tcx()));
1104 /// Given a pattern P like: `[_, ..Q, _]`, where `vec_cmt` is the cmt for `P`, `slice_pat` is
1105 /// the pattern `Q`, returns:
1108 /// * the mutability and region of the slice `Q`
1110 /// These last two bits of info happen to be things that borrowck needs.
1111 pub fn cat_slice_pattern(&self,
1113 slice_pat
: &ast
::Pat
)
1114 -> McResult
<(cmt
<'tcx
>, ast
::Mutability
, ty
::Region
)> {
1115 let slice_ty
= try
!(self.node_ty(slice_pat
.id
));
1116 let (slice_mutbl
, slice_r
) = vec_slice_info(self.tcx(),
1119 let context
= InteriorOffsetKind
::Pattern
;
1120 let cmt_vec
= try
!(self.deref_vec(slice_pat
, vec_cmt
, context
));
1121 let cmt_slice
= try
!(self.cat_index(slice_pat
, cmt_vec
, context
));
1122 return Ok((cmt_slice
, slice_mutbl
, slice_r
));
1124 /// In a pattern like [a, b, ..c], normally `c` has slice type, but if you have [a, b,
1125 /// ..ref c], then the type of `ref c` will be `&&[]`, so to extract the slice details we
1126 /// have to recurse through rptrs.
1127 fn vec_slice_info(tcx
: &ty
::ctxt
,
1130 -> (ast
::Mutability
, ty
::Region
) {
1131 match slice_ty
.sty
{
1132 ty
::ty_rptr(r
, ref mt
) => match mt
.ty
.sty
{
1133 ty
::ty_vec(_
, None
) => (mt
.mutbl
, *r
),
1134 _
=> vec_slice_info(tcx
, pat
, mt
.ty
),
1138 tcx
.sess
.span_bug(pat
.span
,
1139 "type of slice pattern is not a slice");
1145 pub fn cat_imm_interior
<N
:ast_node
>(&self,
1147 base_cmt
: cmt
<'tcx
>,
1148 interior_ty
: Ty
<'tcx
>,
1149 interior
: InteriorKind
)
1151 let ret
= Rc
::new(cmt_
{
1154 mutbl
: base_cmt
.mutbl
.inherit(),
1155 cat
: cat_interior(base_cmt
, interior
),
1159 debug
!("cat_imm_interior ret={}", ret
.repr(self.tcx()));
1163 pub fn cat_downcast
<N
:ast_node
>(&self,
1165 base_cmt
: cmt
<'tcx
>,
1166 downcast_ty
: Ty
<'tcx
>,
1167 variant_did
: ast
::DefId
)
1169 let ret
= Rc
::new(cmt_
{
1172 mutbl
: base_cmt
.mutbl
.inherit(),
1173 cat
: cat_downcast(base_cmt
, variant_did
),
1177 debug
!("cat_downcast ret={}", ret
.repr(self.tcx()));
1181 pub fn cat_pattern
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &ast
::Pat
, mut op
: F
) -> McResult
<()>
1182 where F
: FnMut(&MemCategorizationContext
<'t
, TYPER
>, cmt
<'tcx
>, &ast
::Pat
),
1184 self.cat_pattern_(cmt
, pat
, &mut op
)
1187 // FIXME(#19596) This is a workaround, but there should be a better way to do this
1188 fn cat_pattern_
<F
>(&self, cmt
: cmt
<'tcx
>, pat
: &ast
::Pat
, op
: &mut F
)
1190 where F
: FnMut(&MemCategorizationContext
<'t
, TYPER
>, cmt
<'tcx
>, &ast
::Pat
),
1192 // Here, `cmt` is the categorization for the value being
1193 // matched and pat is the pattern it is being matched against.
1195 // In general, the way that this works is that we walk down
1196 // the pattern, constructing a cmt that represents the path
1197 // that will be taken to reach the value being matched.
1199 // When we encounter named bindings, we take the cmt that has
1200 // been built up and pass it off to guarantee_valid() so that
1201 // we can be sure that the binding will remain valid for the
1202 // duration of the arm.
1204 // (*2) There is subtlety concerning the correspondence between
1205 // pattern ids and types as compared to *expression* ids and
1206 // types. This is explained briefly. on the definition of the
1207 // type `cmt`, so go off and read what it says there, then
1208 // come back and I'll dive into a bit more detail here. :) OK,
1211 // In general, the id of the cmt should be the node that
1212 // "produces" the value---patterns aren't executable code
1213 // exactly, but I consider them to "execute" when they match a
1214 // value, and I consider them to produce the value that was
1215 // matched. So if you have something like:
1222 // In this case, the cmt and the relevant ids would be:
1224 // CMT Id Type of Id Type of cmt
1227 // ^~~~~~~^ `x` from discr @@int @@int
1228 // ^~~~~~~~~~^ `@@y` pattern node @@int @int
1229 // ^~~~~~~~~~~~~^ `@y` pattern node @int int
1231 // You can see that the types of the id and the cmt are in
1232 // sync in the first line, because that id is actually the id
1233 // of an expression. But once we get to pattern ids, the types
1234 // step out of sync again. So you'll see below that we always
1235 // get the type of the *subpattern* and use that.
1237 debug
!("cat_pattern: id={} pat={} cmt={}",
1238 pat
.id
, pprust
::pat_to_string(pat
),
1239 cmt
.repr(self.tcx()));
1241 (*op
)(self, cmt
.clone(), pat
);
1243 let opt_def
= self.tcx().def_map
.borrow().get(&pat
.id
).map(|d
| d
.full_def());
1245 // Note: This goes up here (rather than within the PatEnum arm
1246 // alone) because struct patterns can refer to struct types or
1247 // to struct variants within enums.
1248 let cmt
= match opt_def
{
1249 Some(def
::DefVariant(enum_did
, variant_did
, _
))
1250 // univariant enums do not need downcasts
1251 if !ty
::enum_is_univariant(self.tcx(), enum_did
) => {
1252 self.cat_downcast(pat
, cmt
.clone(), cmt
.ty
, variant_did
)
1258 ast
::PatWild(_
) => {
1262 ast
::PatEnum(_
, None
) => {
1265 ast
::PatEnum(_
, Some(ref subpats
)) => {
1267 Some(def
::DefVariant(..)) => {
1269 for (i
, subpat
) in subpats
.iter().enumerate() {
1270 let subpat_ty
= try
!(self.pat_ty(&**subpat
)); // see (*2)
1273 self.cat_imm_interior(
1274 pat
, cmt
.clone(), subpat_ty
,
1275 InteriorField(PositionalField(i
)));
1277 try
!(self.cat_pattern_(subcmt
, &**subpat
, op
));
1280 Some(def
::DefStruct(..)) => {
1281 for (i
, subpat
) in subpats
.iter().enumerate() {
1282 let subpat_ty
= try
!(self.pat_ty(&**subpat
)); // see (*2)
1284 self.cat_imm_interior(
1285 pat
, cmt
.clone(), subpat_ty
,
1286 InteriorField(PositionalField(i
)));
1287 try
!(self.cat_pattern_(cmt_field
, &**subpat
, op
));
1290 Some(def
::DefConst(..)) | Some(def
::DefAssociatedConst(..)) => {
1291 for subpat
in subpats
{
1292 try
!(self.cat_pattern_(cmt
.clone(), &**subpat
, op
));
1296 self.tcx().sess
.span_bug(
1298 "enum pattern didn't resolve to enum or struct");
1303 ast
::PatQPath(..) => {
1304 // Lone constant: ignore
1307 ast
::PatIdent(_
, _
, Some(ref subpat
)) => {
1308 try
!(self.cat_pattern_(cmt
, &**subpat
, op
));
1311 ast
::PatIdent(_
, _
, None
) => {
1312 // nullary variant or identifier: ignore
1315 ast
::PatStruct(_
, ref field_pats
, _
) => {
1316 // {f1: p1, ..., fN: pN}
1317 for fp
in field_pats
{
1318 let field_ty
= try
!(self.pat_ty(&*fp
.node
.pat
)); // see (*2)
1319 let cmt_field
= self.cat_field(pat
, cmt
.clone(), fp
.node
.ident
.name
, field_ty
);
1320 try
!(self.cat_pattern_(cmt_field
, &*fp
.node
.pat
, op
));
1324 ast
::PatTup(ref subpats
) => {
1326 for (i
, subpat
) in subpats
.iter().enumerate() {
1327 let subpat_ty
= try
!(self.pat_ty(&**subpat
)); // see (*2)
1329 self.cat_imm_interior(
1330 pat
, cmt
.clone(), subpat_ty
,
1331 InteriorField(PositionalField(i
)));
1332 try
!(self.cat_pattern_(subcmt
, &**subpat
, op
));
1336 ast
::PatBox(ref subpat
) | ast
::PatRegion(ref subpat
, _
) => {
1337 // box p1, &p1, &mut p1. we can ignore the mutability of
1338 // PatRegion since that information is already contained
1340 let subcmt
= try
!(self.cat_deref(pat
, cmt
, 0, None
));
1341 try
!(self.cat_pattern_(subcmt
, &**subpat
, op
));
1344 ast
::PatVec(ref before
, ref slice
, ref after
) => {
1345 let context
= InteriorOffsetKind
::Pattern
;
1346 let vec_cmt
= try
!(self.deref_vec(pat
, cmt
, context
));
1347 let elt_cmt
= try
!(self.cat_index(pat
, vec_cmt
, context
));
1348 for before_pat
in before
{
1349 try
!(self.cat_pattern_(elt_cmt
.clone(), &**before_pat
, op
));
1351 if let Some(ref slice_pat
) = *slice
{
1352 let slice_ty
= try
!(self.pat_ty(&**slice_pat
));
1353 let slice_cmt
= self.cat_rvalue_node(pat
.id(), pat
.span(), slice_ty
);
1354 try
!(self.cat_pattern_(slice_cmt
, &**slice_pat
, op
));
1356 for after_pat
in after
{
1357 try
!(self.cat_pattern_(elt_cmt
.clone(), &**after_pat
, op
));
1361 ast
::PatLit(_
) | ast
::PatRange(_
, _
) => {
1366 self.tcx().sess
.span_bug(pat
.span
, "unexpanded macro");
1373 fn overloaded_method_return_ty(&self,
1374 method_ty
: Ty
<'tcx
>)
1377 // When we process an overloaded `*` or `[]` etc, we often
1378 // need to extract the return type of the method. These method
1379 // types are generated by method resolution and always have
1380 // all late-bound regions fully instantiated, so we just want
1381 // to skip past the binder.
1382 ty
::no_late_bound_regions(self.tcx(), &ty
::ty_fn_ret(method_ty
))
1384 .unwrap() // overloaded ops do not diverge, either
1388 #[derive(Copy, Clone, Debug)]
1389 pub enum InteriorSafety
{
1394 #[derive(Clone, Debug)]
1395 pub enum Aliasability
{
1396 FreelyAliasable(AliasableReason
),
1398 ImmutableUnique(Box
<Aliasability
>),
1401 #[derive(Copy, Clone, Debug)]
1402 pub enum AliasableReason
{
1404 AliasableClosure(ast
::NodeId
), // Aliasable due to capture Fn closure env
1406 UnaliasableImmutable
, // Created as needed upon seeing ImmutableUnique
1407 AliasableStatic(InteriorSafety
),
1408 AliasableStaticMut(InteriorSafety
),
1411 impl<'tcx
> cmt_
<'tcx
> {
1412 pub fn guarantor(&self) -> cmt
<'tcx
> {
1413 //! Returns `self` after stripping away any owned pointer derefs or
1414 //! interior content. The return value is basically the `cmt` which
1415 //! determines how long the value in `self` remains live.
1421 cat_deref(_
, _
, UnsafePtr(..)) |
1422 cat_deref(_
, _
, BorrowedPtr(..)) |
1423 cat_deref(_
, _
, Implicit(..)) |
1425 Rc
::new((*self).clone())
1427 cat_downcast(ref b
, _
) |
1428 cat_interior(ref b
, _
) |
1429 cat_deref(ref b
, _
, Unique
) => {
1435 /// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
1436 pub fn freely_aliasable(&self, ctxt
: &ty
::ctxt
<'tcx
>)
1438 // Maybe non-obvious: copied upvars can only be considered
1439 // non-aliasable in once closures, since any other kind can be
1440 // aliased and eventually recused.
1443 cat_deref(ref b
, _
, BorrowedPtr(ty
::MutBorrow
, _
)) |
1444 cat_deref(ref b
, _
, Implicit(ty
::MutBorrow
, _
)) |
1445 cat_deref(ref b
, _
, BorrowedPtr(ty
::UniqueImmBorrow
, _
)) |
1446 cat_deref(ref b
, _
, Implicit(ty
::UniqueImmBorrow
, _
)) |
1447 cat_downcast(ref b
, _
) |
1448 cat_interior(ref b
, _
) => {
1449 // Aliasability depends on base cmt
1450 b
.freely_aliasable(ctxt
)
1453 cat_deref(ref b
, _
, Unique
) => {
1454 let sub
= b
.freely_aliasable(ctxt
);
1455 if b
.mutbl
.is_mutable() {
1456 // Aliasability depends on base cmt alone
1459 // Do not allow mutation through an immutable box.
1460 ImmutableUnique(Box
::new(sub
))
1467 cat_deref(_
, _
, UnsafePtr(..)) => { // yes, it's aliasable, but...
1471 cat_static_item(..) => {
1472 let int_safe
= if ty
::type_interior_is_unsafe(ctxt
, self.ty
) {
1478 if self.mutbl
.is_mutable() {
1479 FreelyAliasable(AliasableStaticMut(int_safe
))
1481 FreelyAliasable(AliasableStatic(int_safe
))
1485 cat_deref(ref base
, _
, BorrowedPtr(ty
::ImmBorrow
, _
)) |
1486 cat_deref(ref base
, _
, Implicit(ty
::ImmBorrow
, _
)) => {
1488 cat_upvar(Upvar{ id, .. }
) =>
1489 FreelyAliasable(AliasableClosure(id
.closure_expr_id
)),
1490 _
=> FreelyAliasable(AliasableBorrowed
)
1496 // Digs down through one or two layers of deref and grabs the cmt
1497 // for the upvar if a note indicates there is one.
1498 pub fn upvar(&self) -> Option
<cmt
<'tcx
>> {
1500 NoteClosureEnv(..) | NoteUpvarRef(..) => {
1501 Some(match self.cat
{
1502 cat_deref(ref inner
, _
, _
) => {
1504 cat_deref(ref inner
, _
, _
) => inner
.clone(),
1505 cat_upvar(..) => inner
.clone(),
1517 pub fn descriptive_string(&self, tcx
: &ty
::ctxt
) -> String
{
1519 cat_static_item
=> {
1520 "static item".to_string()
1523 "non-lvalue".to_string()
1526 match tcx
.map
.find(vid
) {
1527 Some(ast_map
::NodeArg(_
)) => {
1528 "argument".to_string()
1530 _
=> "local variable".to_string()
1533 cat_deref(_
, _
, pk
) => {
1534 let upvar
= self.upvar();
1535 match upvar
.as_ref().map(|i
| &i
.cat
) {
1536 Some(&cat_upvar(ref var
)) => {
1537 var
.user_string(tcx
)
1539 Some(_
) => unreachable
!(),
1543 format
!("indexed content")
1546 format
!("`Box` content")
1549 format
!("dereference of unsafe pointer")
1551 BorrowedPtr(..) => {
1552 format
!("borrowed content")
1558 cat_interior(_
, InteriorField(NamedField(_
))) => {
1561 cat_interior(_
, InteriorField(PositionalField(_
))) => {
1562 "anonymous field".to_string()
1564 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1566 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Index
,
1568 "indexed content".to_string()
1570 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1572 cat_interior(_
, InteriorElement(InteriorOffsetKind
::Pattern
,
1574 "pattern-bound indexed content".to_string()
1576 cat_upvar(ref var
) => {
1577 var
.user_string(tcx
)
1579 cat_downcast(ref cmt
, _
) => {
1580 cmt
.descriptive_string(tcx
)
1586 impl<'tcx
> Repr
<'tcx
> for cmt_
<'tcx
> {
1587 fn repr(&self, tcx
: &ty
::ctxt
<'tcx
>) -> String
{
1588 format
!("{{{} id:{} m:{:?} ty:{}}}",
1596 impl<'tcx
> Repr
<'tcx
> for categorization
<'tcx
> {
1597 fn repr(&self, tcx
: &ty
::ctxt
<'tcx
>) -> String
{
1603 format
!("{:?}", *self)
1605 cat_deref(ref cmt
, derefs
, ptr
) => {
1606 format
!("{}-{}{}->", cmt
.cat
.repr(tcx
), ptr
.repr(tcx
), derefs
)
1608 cat_interior(ref cmt
, interior
) => {
1609 format
!("{}.{}", cmt
.cat
.repr(tcx
), interior
.repr(tcx
))
1611 cat_downcast(ref cmt
, _
) => {
1612 format
!("{}->(enum)", cmt
.cat
.repr(tcx
))
1618 pub fn ptr_sigil(ptr
: PointerKind
) -> &'
static str {
1621 BorrowedPtr(ty
::ImmBorrow
, _
) |
1622 Implicit(ty
::ImmBorrow
, _
) => "&",
1623 BorrowedPtr(ty
::MutBorrow
, _
) |
1624 Implicit(ty
::MutBorrow
, _
) => "&mut",
1625 BorrowedPtr(ty
::UniqueImmBorrow
, _
) |
1626 Implicit(ty
::UniqueImmBorrow
, _
) => "&unique",
1627 UnsafePtr(_
) => "*",
1631 impl<'tcx
> Repr
<'tcx
> for PointerKind
{
1632 fn repr(&self, tcx
: &ty
::ctxt
<'tcx
>) -> String
{
1637 BorrowedPtr(ty
::ImmBorrow
, ref r
) |
1638 Implicit(ty
::ImmBorrow
, ref r
) => {
1639 format
!("&{}", r
.repr(tcx
))
1641 BorrowedPtr(ty
::MutBorrow
, ref r
) |
1642 Implicit(ty
::MutBorrow
, ref r
) => {
1643 format
!("&{} mut", r
.repr(tcx
))
1645 BorrowedPtr(ty
::UniqueImmBorrow
, ref r
) |
1646 Implicit(ty
::UniqueImmBorrow
, ref r
) => {
1647 format
!("&{} uniq", r
.repr(tcx
))
1656 impl<'tcx
> Repr
<'tcx
> for InteriorKind
{
1657 fn repr(&self, _tcx
: &ty
::ctxt
) -> String
{
1659 InteriorField(NamedField(fld
)) => {
1660 token
::get_name(fld
).to_string()
1662 InteriorField(PositionalField(i
)) => format
!("#{}", i
),
1663 InteriorElement(..) => "[]".to_string(),
1668 fn element_kind(t
: Ty
) -> ElementKind
{
1670 ty
::ty_rptr(_
, ty
::mt{ty, ..}
) |
1671 ty
::ty_uniq(ty
) => match ty
.sty
{
1672 ty
::ty_vec(_
, None
) => VecElement
,
1675 ty
::ty_vec(..) => VecElement
,
1680 impl<'tcx
> Repr
<'tcx
> for ty
::ClosureKind
{
1681 fn repr(&self, _
: &ty
::ctxt
) -> String
{
1682 format
!("Upvar({:?})", self)
1686 impl<'tcx
> Repr
<'tcx
> for Upvar
{
1687 fn repr(&self, tcx
: &ty
::ctxt
) -> String
{
1688 format
!("Upvar({})", self.kind
.repr(tcx
))
1692 impl<'tcx
> UserString
<'tcx
> for Upvar
{
1693 fn user_string(&self, _
: &ty
::ctxt
) -> String
{
1694 let kind
= match self.kind
{
1695 ty
::FnClosureKind
=> "Fn",
1696 ty
::FnMutClosureKind
=> "FnMut",
1697 ty
::FnOnceClosureKind
=> "FnOnce",
1699 format
!("captured outer variable in an `{}` closure", kind
)