]> git.proxmox.com Git - rustc.git/blame - src/librustc/middle/mem_categorization.rs
New upstream version 1.18.0+dfsg1
[rustc.git] / src / librustc / middle / mem_categorization.rs
CommitLineData
1a4d82fc 1// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
223e47cc
LB
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
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.
10
1a4d82fc
JJ
11//! # Categorization
12//!
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)
17//!
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
21//! forms):
22//!
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
27//!
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.
32//!
33//! Now, cat_expr() classifies the expression Expr and the address A=ToAddr(Expr)
34//! as follows:
35//!
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
41//!
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.
46//!
47//! ## By-reference upvars
48//!
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:
52//!
53//! let mut x = 3;
54//! let y = 5;
55//! let inc = || x += y;
56//!
57//! Then when we categorize `x` (*within* the closure) we would yield a
92a42be0 58//! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
1a4d82fc
JJ
59//! tied to `x`. The type of `x'` will be a borrowed pointer.
60
61#![allow(non_camel_case_types)]
62
63pub use self::PointerKind::*;
64pub use self::InteriorKind::*;
65pub use self::FieldName::*;
66pub use self::ElementKind::*;
67pub use self::MutabilityCategory::*;
1a4d82fc
JJ
68pub use self::AliasableReason::*;
69pub use self::Note::*;
1a4d82fc 70
c34b1796
AL
71use self::Aliasability::*;
72
54a0048b 73use hir::def_id::DefId;
32a655c1 74use hir::map as hir_map;
a7813a04 75use infer::InferCtxt;
c30ab7b3 76use hir::def::{Def, CtorKind};
54a0048b
SL
77use ty::adjustment;
78use ty::{self, Ty, TyCtxt};
1a4d82fc 79
54a0048b 80use hir::{MutImmutable, MutMutable, PatKind};
3157f602 81use hir::pat_util::EnumerateAndAdjustIterator;
54a0048b 82use hir;
223e47cc 83use syntax::ast;
3157f602 84use syntax_pos::Span;
223e47cc 85
62682a34 86use std::fmt;
1a4d82fc
JJ
87use std::rc::Rc;
88
62682a34 89#[derive(Clone, PartialEq)]
92a42be0 90pub enum Categorization<'tcx> {
32a655c1
SL
91 // temporary val, argument is its scope
92 Rvalue(&'tcx ty::Region, &'tcx ty::Region),
92a42be0
SL
93 StaticItem,
94 Upvar(Upvar), // upvar referenced by closure env
95 Local(ast::NodeId), // local variable
9e0c209e 96 Deref(cmt<'tcx>, usize, PointerKind<'tcx>), // deref of a ptr
92a42be0
SL
97 Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc
98 Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1)
1a4d82fc
JJ
99
100 // (*1) downcast is only required if the enum has more than one variant
970d7e83
LB
101}
102
1a4d82fc 103// Represents any kind of upvar
62682a34 104#[derive(Clone, Copy, PartialEq)]
1a4d82fc
JJ
105pub struct Upvar {
106 pub id: ty::UpvarId,
85aaf69f 107 pub kind: ty::ClosureKind
223e47cc
LB
108}
109
110// different kinds of pointers:
62682a34 111#[derive(Clone, Copy, PartialEq, Eq, Hash)]
9e0c209e 112pub enum PointerKind<'tcx> {
1a4d82fc
JJ
113 /// `Box<T>`
114 Unique,
115
116 /// `&T`
9e0c209e 117 BorrowedPtr(ty::BorrowKind, &'tcx ty::Region),
1a4d82fc
JJ
118
119 /// `*T`
e9174d1e 120 UnsafePtr(hir::Mutability),
1a4d82fc
JJ
121
122 /// Implicit deref of the `&T` that results from an overloaded index `[]`.
9e0c209e 123 Implicit(ty::BorrowKind, &'tcx ty::Region),
223e47cc
LB
124}
125
970d7e83
LB
126// We use the term "interior" to mean "something reachable from the
127// base without a pointer dereference", e.g. a field
62682a34 128#[derive(Clone, Copy, PartialEq, Eq, Hash)]
970d7e83
LB
129pub enum InteriorKind {
130 InteriorField(FieldName),
85aaf69f 131 InteriorElement(InteriorOffsetKind, ElementKind),
223e47cc
LB
132}
133
85aaf69f 134#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
970d7e83 135pub enum FieldName {
1a4d82fc 136 NamedField(ast::Name),
c34b1796 137 PositionalField(usize)
223e47cc
LB
138}
139
85aaf69f
SL
140#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
141pub enum InteriorOffsetKind {
142 Index, // e.g. `array_expr[index_expr]`
143 Pattern, // e.g. `fn foo([_, a, _, _]: [A; 4]) { ... }`
144}
145
146#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
970d7e83
LB
147pub enum ElementKind {
148 VecElement,
970d7e83
LB
149 OtherElement,
150}
151
85aaf69f 152#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
223e47cc
LB
153pub enum MutabilityCategory {
154 McImmutable, // Immutable.
223e47cc 155 McDeclared, // Directly declared as mutable.
1a4d82fc
JJ
156 McInherited, // Inherited from the fact that owner is mutable.
157}
158
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.
85aaf69f 164#[derive(Clone, Copy, PartialEq, Debug)]
1a4d82fc
JJ
165pub enum Note {
166 NoteClosureEnv(ty::UpvarId), // Deref through closure env
167 NoteUpvarRef(ty::UpvarId), // Deref through by-ref upvar
168 NoteNone // Nothing special
223e47cc
LB
169}
170
970d7e83
LB
171// `cmt`: "Category, Mutability, and Type".
172//
223e47cc
LB
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.
176//
970d7e83
LB
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
1a4d82fc 183// (`@T`). So use `cmt.ty` to find the type of the value in a consistent
970d7e83 184// fashion. For more details, see the method `cat_pattern`
62682a34 185#[derive(Clone, PartialEq)]
1a4d82fc
JJ
186pub struct cmt_<'tcx> {
187 pub id: ast::NodeId, // id of expr/pat producing this value
188 pub span: Span, // span of same expr/pat
92a42be0 189 pub cat: Categorization<'tcx>, // categorization of expr
1a4d82fc
JJ
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
223e47cc
LB
193}
194
1a4d82fc 195pub type cmt<'tcx> = Rc<cmt_<'tcx>>;
223e47cc 196
cc61c64b
XL
197pub enum ImmutabilityBlame<'tcx> {
198 ImmLocal(ast::NodeId),
199 ClosureEnv(ast::NodeId),
200 LocalDeref(ast::NodeId),
201 AdtFieldDeref(&'tcx ty::AdtDef, &'tcx ty::FieldDef)
202}
32a655c1 203
cc61c64b
XL
204impl<'tcx> cmt_<'tcx> {
205 fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
206 {
207 let adt_def = match self.ty.sty {
208 ty::TyAdt(def, _) => def,
209 ty::TyTuple(..) => return None,
210 // closures get `Categorization::Upvar` rather than `Categorization::Interior`
211 _ => bug!("interior cmt {:?} is not an ADT", self)
212 };
213 let variant_def = match self.cat {
214 Categorization::Downcast(_, variant_did) => {
215 adt_def.variant_with_id(variant_did)
32a655c1 216 }
cc61c64b
XL
217 _ => {
218 assert!(adt_def.is_univariant());
219 &adt_def.variants[0]
32a655c1 220 }
cc61c64b
XL
221 };
222 let field_def = match field_name {
223 NamedField(name) => variant_def.field_named(name),
224 PositionalField(idx) => &variant_def.fields[idx]
225 };
226 Some((adt_def, field_def))
32a655c1
SL
227 }
228
cc61c64b 229 pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
32a655c1 230 match self.cat {
cc61c64b
XL
231 Categorization::Deref(ref base_cmt, _, BorrowedPtr(ty::ImmBorrow, _)) |
232 Categorization::Deref(ref base_cmt, _, Implicit(ty::ImmBorrow, _)) => {
233 // try to figure out where the immutable reference came from
234 match base_cmt.cat {
235 Categorization::Local(node_id) =>
236 Some(ImmutabilityBlame::LocalDeref(node_id)),
237 Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
238 base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| {
239 ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)
240 })
241 }
242 Categorization::Upvar(Upvar { id, .. }) => {
243 if let NoteClosureEnv(..) = self.note {
244 Some(ImmutabilityBlame::ClosureEnv(id.closure_expr_id))
245 } else {
246 None
32a655c1
SL
247 }
248 }
cc61c64b 249 _ => None
32a655c1
SL
250 }
251 }
cc61c64b
XL
252 Categorization::Local(node_id) => {
253 Some(ImmutabilityBlame::ImmLocal(node_id))
254 }
255 Categorization::Rvalue(..) |
256 Categorization::Upvar(..) |
257 Categorization::Deref(.., UnsafePtr(..)) => {
258 // This should not be reachable up to inference limitations.
259 None
260 }
261 Categorization::Interior(ref base_cmt, _) |
262 Categorization::Downcast(ref base_cmt, _) |
263 Categorization::Deref(ref base_cmt, _, _) => {
264 base_cmt.immutability_blame()
265 }
266 Categorization::StaticItem => {
267 // Do we want to do something here?
268 None
269 }
32a655c1
SL
270 }
271 }
272}
273
1a4d82fc
JJ
274pub trait ast_node {
275 fn id(&self) -> ast::NodeId;
276 fn span(&self) -> Span;
223e47cc
LB
277}
278
e9174d1e 279impl ast_node for hir::Expr {
1a4d82fc
JJ
280 fn id(&self) -> ast::NodeId { self.id }
281 fn span(&self) -> Span { self.span }
223e47cc
LB
282}
283
e9174d1e 284impl ast_node for hir::Pat {
1a4d82fc
JJ
285 fn id(&self) -> ast::NodeId { self.id }
286 fn span(&self) -> Span { self.span }
223e47cc
LB
287}
288
c1a9b12d 289#[derive(Copy, Clone)]
a7813a04
XL
290pub struct MemCategorizationContext<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
291 pub infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
3157f602
XL
292 options: MemCategorizationOptions,
293}
294
295#[derive(Copy, Clone, Default)]
296pub struct MemCategorizationOptions {
297 // If true, then when analyzing a closure upvar, if the closure
298 // has a missing kind, we treat it like a Fn closure. When false,
299 // we ICE if the closure has a missing kind. Should be false
300 // except during closure kind inference. It is used by the
301 // mem-categorization code to be able to have stricter assertions
302 // (which are always true except during upvar inference).
303 pub during_closure_kind_inference: bool,
c34b1796 304}
1a4d82fc
JJ
305
306pub type McResult<T> = Result<T, ()>;
307
1a4d82fc 308impl MutabilityCategory {
e9174d1e 309 pub fn from_mutbl(m: hir::Mutability) -> MutabilityCategory {
c34b1796 310 let ret = match m {
1a4d82fc
JJ
311 MutImmutable => McImmutable,
312 MutMutable => McDeclared
c34b1796
AL
313 };
314 debug!("MutabilityCategory::{}({:?}) => {:?}",
315 "from_mutbl", m, ret);
316 ret
1a4d82fc 317 }
223e47cc 318
1a4d82fc 319 pub fn from_borrow_kind(borrow_kind: ty::BorrowKind) -> MutabilityCategory {
c34b1796 320 let ret = match borrow_kind {
1a4d82fc
JJ
321 ty::ImmBorrow => McImmutable,
322 ty::UniqueImmBorrow => McImmutable,
323 ty::MutBorrow => McDeclared,
c34b1796
AL
324 };
325 debug!("MutabilityCategory::{}({:?}) => {:?}",
326 "from_borrow_kind", borrow_kind, ret);
327 ret
1a4d82fc 328 }
223e47cc 329
c34b1796
AL
330 fn from_pointer_kind(base_mutbl: MutabilityCategory,
331 ptr: PointerKind) -> MutabilityCategory {
332 let ret = match ptr {
1a4d82fc
JJ
333 Unique => {
334 base_mutbl.inherit()
335 }
336 BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => {
337 MutabilityCategory::from_borrow_kind(borrow_kind)
338 }
339 UnsafePtr(m) => {
340 MutabilityCategory::from_mutbl(m)
341 }
c34b1796
AL
342 };
343 debug!("MutabilityCategory::{}({:?}, {:?}) => {:?}",
344 "from_pointer_kind", base_mutbl, ptr, ret);
345 ret
223e47cc 346 }
223e47cc 347
a7813a04 348 fn from_local(tcx: TyCtxt, id: ast::NodeId) -> MutabilityCategory {
32a655c1
SL
349 let ret = match tcx.hir.get(id) {
350 hir_map::NodeLocal(p) => match p.node {
9e0c209e 351 PatKind::Binding(bind_mode, ..) => {
e9174d1e 352 if bind_mode == hir::BindByValue(hir::MutMutable) {
1a4d82fc
JJ
353 McDeclared
354 } else {
355 McImmutable
356 }
357 }
54a0048b 358 _ => span_bug!(p.span, "expected identifier pattern")
1a4d82fc 359 },
32a655c1 360 _ => span_bug!(tcx.hir.span(id), "expected identifier pattern")
c34b1796
AL
361 };
362 debug!("MutabilityCategory::{}(tcx, id={:?}) => {:?}",
363 "from_local", id, ret);
364 ret
223e47cc
LB
365 }
366
970d7e83 367 pub fn inherit(&self) -> MutabilityCategory {
c34b1796 368 let ret = match *self {
223e47cc 369 McImmutable => McImmutable,
223e47cc 370 McDeclared => McInherited,
1a4d82fc 371 McInherited => McInherited,
c34b1796
AL
372 };
373 debug!("{:?}.inherit() => {:?}", self, ret);
374 ret
223e47cc
LB
375 }
376
970d7e83 377 pub fn is_mutable(&self) -> bool {
c34b1796 378 let ret = match *self {
1a4d82fc
JJ
379 McImmutable => false,
380 McInherited => true,
381 McDeclared => true,
c34b1796
AL
382 };
383 debug!("{:?}.is_mutable() => {:?}", self, ret);
384 ret
223e47cc
LB
385 }
386
970d7e83 387 pub fn is_immutable(&self) -> bool {
c34b1796 388 let ret = match *self {
223e47cc 389 McImmutable => true,
1a4d82fc 390 McDeclared | McInherited => false
c34b1796
AL
391 };
392 debug!("{:?}.is_immutable() => {:?}", self, ret);
393 ret
223e47cc
LB
394 }
395
970d7e83 396 pub fn to_user_str(&self) -> &'static str {
223e47cc 397 match *self {
970d7e83
LB
398 McDeclared | McInherited => "mutable",
399 McImmutable => "immutable",
223e47cc
LB
400 }
401 }
402}
403
a7813a04
XL
404impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
405 pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>)
406 -> MemCategorizationContext<'a, 'gcx, 'tcx> {
3157f602
XL
407 MemCategorizationContext::with_options(infcx, MemCategorizationOptions::default())
408 }
409
410 pub fn with_options(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
411 options: MemCategorizationOptions)
412 -> MemCategorizationContext<'a, 'gcx, 'tcx> {
413 MemCategorizationContext {
414 infcx: infcx,
415 options: options,
416 }
1a4d82fc
JJ
417 }
418
a7813a04
XL
419 fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
420 self.infcx.tcx
1a4d82fc
JJ
421 }
422
e9174d1e 423 fn expr_ty(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
a7813a04 424 match self.infcx.node_ty(expr.id) {
c1a9b12d
SL
425 Ok(t) => Ok(t),
426 Err(()) => {
427 debug!("expr_ty({:?}) yielded Err", expr);
428 Err(())
429 }
430 }
1a4d82fc
JJ
431 }
432
e9174d1e 433 fn expr_ty_adjusted(&self, expr: &hir::Expr) -> McResult<Ty<'tcx>> {
c30ab7b3 434 self.infcx.expr_ty_adjusted(expr)
970d7e83
LB
435 }
436
1a4d82fc 437 fn node_ty(&self, id: ast::NodeId) -> McResult<Ty<'tcx>> {
a7813a04 438 self.infcx.node_ty(id)
970d7e83
LB
439 }
440
e9174d1e 441 fn pat_ty(&self, pat: &hir::Pat) -> McResult<Ty<'tcx>> {
a7813a04 442 let base_ty = self.infcx.node_ty(pat.id)?;
1a4d82fc
JJ
443 // FIXME (Issue #18207): This code detects whether we are
444 // looking at a `ref x`, and if so, figures out what the type
445 // *being borrowed* is. But ideally we would put in a more
446 // fundamental fix to this conflated use of the node id.
447 let ret_ty = match pat.node {
9e0c209e 448 PatKind::Binding(hir::BindByRef(_), ..) => {
1a4d82fc
JJ
449 // a bind-by-ref means that the base_ty will be the type of the ident itself,
450 // but what we want here is the type of the underlying value being borrowed.
451 // So peel off one-level, turning the &T into T.
e9174d1e 452 match base_ty.builtin_deref(false, ty::NoPreference) {
1a4d82fc 453 Some(t) => t.ty,
cc61c64b
XL
454 None => {
455 debug!("By-ref binding of non-derefable type {:?}", base_ty);
456 return Err(());
457 }
1a4d82fc
JJ
458 }
459 }
460 _ => base_ty,
461 };
62682a34
SL
462 debug!("pat_ty(pat={:?}) base_ty={:?} ret_ty={:?}",
463 pat, base_ty, ret_ty);
1a4d82fc
JJ
464 Ok(ret_ty)
465 }
466
e9174d1e 467 pub fn cat_expr(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
32a655c1 468 match self.infcx.tables.borrow().adjustments.get(&expr.id) {
223e47cc
LB
469 None => {
470 // No adjustments.
471 self.cat_expr_unadjusted(expr)
472 }
473
1a4d82fc 474 Some(adjustment) => {
c30ab7b3
SL
475 match adjustment.kind {
476 adjustment::Adjust::DerefRef {
477 autoderefs,
478 autoref: None,
479 unsize: false
480 } => {
9346a6ac
AL
481 // Equivalent to *expr or something similar.
482 self.cat_expr_autoderefd(expr, autoderefs)
483 }
484
c30ab7b3
SL
485 adjustment::Adjust::NeverToAny |
486 adjustment::Adjust::ReifyFnPointer |
487 adjustment::Adjust::UnsafeFnPointer |
8bb4bdeb 488 adjustment::Adjust::ClosureFnPointer |
c30ab7b3
SL
489 adjustment::Adjust::MutToConstPointer |
490 adjustment::Adjust::DerefRef {..} => {
62682a34
SL
491 debug!("cat_expr({:?}): {:?}",
492 adjustment,
493 expr);
1a4d82fc 494 // Result is an rvalue.
54a0048b 495 let expr_ty = self.expr_ty_adjusted(expr)?;
1a4d82fc
JJ
496 Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
497 }
1a4d82fc 498 }
223e47cc
LB
499 }
500 }
501 }
502
1a4d82fc 503 pub fn cat_expr_autoderefd(&self,
e9174d1e 504 expr: &hir::Expr,
c34b1796 505 autoderefs: usize)
1a4d82fc 506 -> McResult<cmt<'tcx>> {
54a0048b 507 let mut cmt = self.cat_expr_unadjusted(expr)?;
62682a34 508 debug!("cat_expr_autoderefd: autoderefs={}, cmt={:?}",
1a4d82fc 509 autoderefs,
62682a34 510 cmt);
85aaf69f 511 for deref in 1..autoderefs + 1 {
9e0c209e 512 cmt = self.cat_deref(expr, cmt, deref)?;
223e47cc 513 }
1a4d82fc 514 return Ok(cmt);
223e47cc
LB
515 }
516
e9174d1e 517 pub fn cat_expr_unadjusted(&self, expr: &hir::Expr) -> McResult<cmt<'tcx>> {
62682a34 518 debug!("cat_expr: id={} expr={:?}", expr.id, expr);
223e47cc 519
54a0048b 520 let expr_ty = self.expr_ty(expr)?;
223e47cc 521 match expr.node {
e9174d1e 522 hir::ExprUnary(hir::UnDeref, ref e_base) => {
54a0048b 523 let base_cmt = self.cat_expr(&e_base)?;
9e0c209e 524 self.cat_deref(expr, base_cmt, 0)
223e47cc
LB
525 }
526
e9174d1e 527 hir::ExprField(ref base, f_name) => {
54a0048b 528 let base_cmt = self.cat_expr(&base)?;
62682a34 529 debug!("cat_expr(cat_field): id={} expr={:?} base={:?}",
1a4d82fc 530 expr.id,
62682a34
SL
531 expr,
532 base_cmt);
b039eaaf 533 Ok(self.cat_field(expr, base_cmt, f_name.node, expr_ty))
1a4d82fc 534 }
223e47cc 535
e9174d1e 536 hir::ExprTupField(ref base, idx) => {
54a0048b 537 let base_cmt = self.cat_expr(&base)?;
1a4d82fc 538 Ok(self.cat_tup_field(expr, base_cmt, idx.node, expr_ty))
223e47cc
LB
539 }
540
e9174d1e 541 hir::ExprIndex(ref base, _) => {
1a4d82fc 542 let method_call = ty::MethodCall::expr(expr.id());
a7813a04 543 match self.infcx.node_method_ty(method_call) {
1a4d82fc
JJ
544 Some(method_ty) => {
545 // If this is an index implemented by a method call, then it
546 // will include an implicit deref of the result.
547 let ret_ty = self.overloaded_method_return_ty(method_ty);
548
549 // The index method always returns an `&T`, so
550 // dereference it to find the result type.
551 let elem_ty = match ret_ty.sty {
62682a34 552 ty::TyRef(_, mt) => mt.ty,
1a4d82fc 553 _ => {
62682a34
SL
554 debug!("cat_expr_unadjusted: return type of overloaded index is {:?}?",
555 ret_ty);
1a4d82fc
JJ
556 return Err(());
557 }
558 };
223e47cc 559
1a4d82fc
JJ
560 // The call to index() returns a `&T` value, which
561 // is an rvalue. That is what we will be
562 // dereferencing.
563 let base_cmt = self.cat_rvalue_node(expr.id(), expr.span(), ret_ty);
9e0c209e 564 Ok(self.cat_deref_common(expr, base_cmt, 1, elem_ty, true))
1a4d82fc
JJ
565 }
566 None => {
9e0c209e 567 self.cat_index(expr, self.cat_expr(&base)?, InteriorOffsetKind::Index)
1a4d82fc
JJ
568 }
569 }
223e47cc
LB
570 }
571
476ff2be
SL
572 hir::ExprPath(ref qpath) => {
573 let def = self.infcx.tables.borrow().qpath_def(qpath, expr.id);
574 self.cat_def(expr.id, expr.span, expr_ty, def)
223e47cc
LB
575 }
576
9cc50fc6 577 hir::ExprType(ref e, _) => {
7453a54e 578 self.cat_expr(&e)
9cc50fc6
SL
579 }
580
e9174d1e
SL
581 hir::ExprAddrOf(..) | hir::ExprCall(..) |
582 hir::ExprAssign(..) | hir::ExprAssignOp(..) |
583 hir::ExprClosure(..) | hir::ExprRet(..) |
54a0048b 584 hir::ExprUnary(..) |
e9174d1e 585 hir::ExprMethodCall(..) | hir::ExprCast(..) |
c30ab7b3 586 hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprIf(..) |
e9174d1e
SL
587 hir::ExprBinary(..) | hir::ExprWhile(..) |
588 hir::ExprBlock(..) | hir::ExprLoop(..) | hir::ExprMatch(..) |
589 hir::ExprLit(..) | hir::ExprBreak(..) |
590 hir::ExprAgain(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) |
591 hir::ExprInlineAsm(..) | hir::ExprBox(..) => {
1a4d82fc
JJ
592 Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty))
593 }
223e47cc
LB
594 }
595 }
596
970d7e83 597 pub fn cat_def(&self,
1a4d82fc
JJ
598 id: ast::NodeId,
599 span: Span,
600 expr_ty: Ty<'tcx>,
7453a54e 601 def: Def)
1a4d82fc 602 -> McResult<cmt<'tcx>> {
62682a34
SL
603 debug!("cat_def: id={} expr={:?} def={:?}",
604 id, expr_ty, def);
1a4d82fc 605
223e47cc 606 match def {
c30ab7b3 607 Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) |
7453a54e 608 Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => {
1a4d82fc
JJ
609 Ok(self.cat_rvalue_node(id, span, expr_ty))
610 }
7453a54e 611
7453a54e 612 Def::Static(_, mutbl) => {
1a4d82fc 613 Ok(Rc::new(cmt_ {
970d7e83
LB
614 id:id,
615 span:span,
92a42be0 616 cat:Categorization::StaticItem,
1a4d82fc
JJ
617 mutbl: if mutbl { McDeclared } else { McImmutable},
618 ty:expr_ty,
619 note: NoteNone
620 }))
223e47cc
LB
621 }
622
9e0c209e 623 Def::Upvar(def_id, _, fn_node_id) => {
32a655c1 624 let var_id = self.tcx().hir.as_local_node_id(def_id).unwrap();
54a0048b 625 let ty = self.node_ty(fn_node_id)?;
1a4d82fc 626 match ty.sty {
62682a34 627 ty::TyClosure(closure_id, _) => {
a7813a04 628 match self.infcx.closure_kind(closure_id) {
85aaf69f
SL
629 Some(kind) => {
630 self.cat_upvar(id, span, var_id, fn_node_id, kind)
631 }
632 None => {
3157f602
XL
633 if !self.options.during_closure_kind_inference {
634 span_bug!(
635 span,
636 "No closure kind for {:?}",
637 closure_id);
638 }
639
640 // during closure kind inference, we
641 // don't know the closure kind yet, but
642 // it's ok because we detect that we are
643 // accessing an upvar and handle that
644 // case specially anyhow. Use Fn
645 // arbitrarily.
646 self.cat_upvar(id, span, var_id, fn_node_id, ty::ClosureKind::Fn)
85aaf69f
SL
647 }
648 }
1a4d82fc
JJ
649 }
650 _ => {
54a0048b 651 span_bug!(
1a4d82fc 652 span,
54a0048b
SL
653 "Upvar of non-closure {} - {:?}",
654 fn_node_id,
655 ty);
1a4d82fc
JJ
656 }
657 }
658 }
223e47cc 659
9e0c209e 660 Def::Local(def_id) => {
32a655c1 661 let vid = self.tcx().hir.as_local_node_id(def_id).unwrap();
1a4d82fc 662 Ok(Rc::new(cmt_ {
970d7e83
LB
663 id: id,
664 span: span,
92a42be0 665 cat: Categorization::Local(vid),
1a4d82fc
JJ
666 mutbl: MutabilityCategory::from_local(self.tcx(), vid),
667 ty: expr_ty,
668 note: NoteNone
669 }))
223e47cc 670 }
9cc50fc6 671
c30ab7b3 672 def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def)
1a4d82fc
JJ
673 }
674 }
223e47cc 675
1a4d82fc
JJ
676 // Categorize an upvar, complete with invisible derefs of closure
677 // environment and upvar reference as appropriate.
678 fn cat_upvar(&self,
679 id: ast::NodeId,
680 span: Span,
681 var_id: ast::NodeId,
682 fn_node_id: ast::NodeId,
85aaf69f
SL
683 kind: ty::ClosureKind)
684 -> McResult<cmt<'tcx>>
685 {
686 // An upvar can have up to 3 components. We translate first to a
92a42be0 687 // `Categorization::Upvar`, which is itself a fiction -- it represents the reference to the
85aaf69f
SL
688 // field from the environment.
689 //
92a42be0 690 // `Categorization::Upvar`. Next, we add a deref through the implicit
1a4d82fc
JJ
691 // environment pointer with an anonymous free region 'env and
692 // appropriate borrow kind for closure kinds that take self by
693 // reference. Finally, if the upvar was captured
694 // by-reference, we add a deref through that reference. The
695 // region of this reference is an inference variable 'up that
696 // was previously generated and recorded in the upvar borrow
697 // map. The borrow kind bk is inferred by based on how the
698 // upvar is used.
699 //
700 // This results in the following table for concrete closure
701 // types:
702 //
703 // | move | ref
704 // ---------------+----------------------+-------------------------------
705 // Fn | copied -> &'env | upvar -> &'env -> &'up bk
706 // FnMut | copied -> &'env mut | upvar -> &'env mut -> &'up bk
707 // FnOnce | copied | upvar -> &'up bk
1a4d82fc
JJ
708
709 let upvar_id = ty::UpvarId { var_id: var_id,
710 closure_expr_id: fn_node_id };
54a0048b 711 let var_ty = self.node_ty(var_id)?;
1a4d82fc
JJ
712
713 // Mutability of original variable itself
714 let var_mutbl = MutabilityCategory::from_local(self.tcx(), var_id);
715
85aaf69f
SL
716 // Construct the upvar. This represents access to the field
717 // from the environment (perhaps we should eventually desugar
718 // this field further, but it will do for now).
719 let cmt_result = cmt_ {
720 id: id,
721 span: span,
92a42be0 722 cat: Categorization::Upvar(Upvar {id: upvar_id, kind: kind}),
85aaf69f
SL
723 mutbl: var_mutbl,
724 ty: var_ty,
725 note: NoteNone
1a4d82fc 726 };
223e47cc 727
85aaf69f
SL
728 // If this is a `FnMut` or `Fn` closure, then the above is
729 // conceptually a `&mut` or `&` reference, so we have to add a
730 // deref.
731 let cmt_result = match kind {
54a0048b 732 ty::ClosureKind::FnOnce => {
85aaf69f
SL
733 cmt_result
734 }
54a0048b 735 ty::ClosureKind::FnMut => {
85aaf69f
SL
736 self.env_deref(id, span, upvar_id, var_mutbl, ty::MutBorrow, cmt_result)
737 }
54a0048b 738 ty::ClosureKind::Fn => {
85aaf69f
SL
739 self.env_deref(id, span, upvar_id, var_mutbl, ty::ImmBorrow, cmt_result)
740 }
741 };
1a4d82fc 742
85aaf69f
SL
743 // If this is a by-ref capture, then the upvar we loaded is
744 // actually a reference, so we have to add an implicit deref
745 // for that.
746 let upvar_id = ty::UpvarId { var_id: var_id,
747 closure_expr_id: fn_node_id };
a7813a04 748 let upvar_capture = self.infcx.upvar_capture(upvar_id).unwrap();
85aaf69f
SL
749 let cmt_result = match upvar_capture {
750 ty::UpvarCapture::ByValue => {
751 cmt_result
752 }
753 ty::UpvarCapture::ByRef(upvar_borrow) => {
754 let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region);
755 cmt_ {
1a4d82fc
JJ
756 id: id,
757 span: span,
92a42be0 758 cat: Categorization::Deref(Rc::new(cmt_result), 0, ptr),
85aaf69f 759 mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind),
1a4d82fc 760 ty: var_ty,
85aaf69f 761 note: NoteUpvarRef(upvar_id)
1a4d82fc 762 }
85aaf69f
SL
763 }
764 };
223e47cc 765
c34b1796 766 let ret = Rc::new(cmt_result);
62682a34 767 debug!("cat_upvar ret={:?}", ret);
c34b1796 768 Ok(ret)
85aaf69f 769 }
1a4d82fc 770
85aaf69f
SL
771 fn env_deref(&self,
772 id: ast::NodeId,
773 span: Span,
774 upvar_id: ty::UpvarId,
775 upvar_mutbl: MutabilityCategory,
776 env_borrow_kind: ty::BorrowKind,
777 cmt_result: cmt_<'tcx>)
778 -> cmt_<'tcx>
779 {
780 // Look up the node ID of the closure body so we can construct
781 // a free region within it
782 let fn_body_id = {
32a655c1
SL
783 let fn_expr = match self.tcx().hir.find(upvar_id.closure_expr_id) {
784 Some(hir_map::NodeExpr(e)) => e,
54a0048b 785 _ => bug!()
85aaf69f 786 };
1a4d82fc 787
85aaf69f 788 match fn_expr.node {
32a655c1 789 hir::ExprClosure(.., body_id, _) => body_id.node_id,
54a0048b 790 _ => bug!()
223e47cc 791 }
85aaf69f
SL
792 };
793
794 // Region of environment pointer
9e0c209e 795 let env_region = self.tcx().mk_region(ty::ReFree(ty::FreeRegion {
85aaf69f
SL
796 // The environment of a closure is guaranteed to
797 // outlive any bindings introduced in the body of the
798 // closure itself.
e9174d1e 799 scope: self.tcx().region_maps.item_extent(fn_body_id),
85aaf69f 800 bound_region: ty::BrEnv
9e0c209e 801 }));
85aaf69f
SL
802
803 let env_ptr = BorrowedPtr(env_borrow_kind, env_region);
804
805 let var_ty = cmt_result.ty;
806
807 // We need to add the env deref. This means
808 // that the above is actually immutable and
809 // has a ref type. However, nothing should
810 // actually look at the type, so we can get
62682a34 811 // away with stuffing a `TyError` in there
85aaf69f
SL
812 // instead of bothering to construct a proper
813 // one.
814 let cmt_result = cmt_ {
815 mutbl: McImmutable,
816 ty: self.tcx().types.err,
817 ..cmt_result
818 };
819
820 let mut deref_mutbl = MutabilityCategory::from_borrow_kind(env_borrow_kind);
821
822 // Issue #18335. If variable is declared as immutable, override the
823 // mutability from the environment and substitute an `&T` anyway.
824 match upvar_mutbl {
825 McImmutable => { deref_mutbl = McImmutable; }
826 McDeclared | McInherited => { }
827 }
828
c34b1796 829 let ret = cmt_ {
85aaf69f
SL
830 id: id,
831 span: span,
92a42be0 832 cat: Categorization::Deref(Rc::new(cmt_result), 0, env_ptr),
85aaf69f
SL
833 mutbl: deref_mutbl,
834 ty: var_ty,
835 note: NoteClosureEnv(upvar_id)
c34b1796
AL
836 };
837
62682a34 838 debug!("env_deref ret {:?}", ret);
c34b1796
AL
839
840 ret
223e47cc
LB
841 }
842
9346a6ac
AL
843 /// Returns the lifetime of a temporary created by expr with id `id`.
844 /// This could be `'static` if `id` is part of a constant expression.
32a655c1
SL
845 pub fn temporary_scope(&self, id: ast::NodeId) -> (&'tcx ty::Region, &'tcx ty::Region)
846 {
847 let (scope, old_scope) =
848 self.tcx().region_maps.old_and_new_temporary_scope(id);
849 (self.tcx().mk_region(match scope {
9346a6ac
AL
850 Some(scope) => ty::ReScope(scope),
851 None => ty::ReStatic
32a655c1
SL
852 }),
853 self.tcx().mk_region(match old_scope {
854 Some(scope) => ty::ReScope(scope),
855 None => ty::ReStatic
856 }))
9346a6ac
AL
857 }
858
1a4d82fc
JJ
859 pub fn cat_rvalue_node(&self,
860 id: ast::NodeId,
861 span: Span,
862 expr_ty: Ty<'tcx>)
863 -> cmt<'tcx> {
32a655c1
SL
864 let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned()
865 .unwrap_or(false);
85aaf69f 866
cc61c64b 867 // When the corresponding feature isn't toggled, only promote `[T; 0]`.
32a655c1
SL
868 let promotable = match expr_ty.sty {
869 ty::TyArray(_, 0) => true,
cc61c64b 870 _ => promotable && self.tcx().sess.features.borrow().rvalue_static_promotion,
85aaf69f
SL
871 };
872
9346a6ac
AL
873 // Compute maximum lifetime of this rvalue. This is 'static if
874 // we can promote to a constant, otherwise equal to enclosing temp
875 // lifetime.
32a655c1 876 let (re, old_re) = if promotable {
cc61c64b
XL
877 (self.tcx().types.re_static,
878 self.tcx().types.re_static)
d9579d0f 879 } else {
32a655c1 880 self.temporary_scope(id)
85aaf69f 881 };
32a655c1 882 let ret = self.cat_rvalue(id, span, re, old_re, expr_ty);
62682a34 883 debug!("cat_rvalue_node ret {:?}", ret);
c34b1796 884 ret
223e47cc
LB
885 }
886
1a4d82fc
JJ
887 pub fn cat_rvalue(&self,
888 cmt_id: ast::NodeId,
889 span: Span,
9e0c209e 890 temp_scope: &'tcx ty::Region,
32a655c1 891 old_temp_scope: &'tcx ty::Region,
1a4d82fc 892 expr_ty: Ty<'tcx>) -> cmt<'tcx> {
c34b1796 893 let ret = Rc::new(cmt_ {
1a4d82fc
JJ
894 id:cmt_id,
895 span:span,
32a655c1 896 cat:Categorization::Rvalue(temp_scope, old_temp_scope),
1a4d82fc
JJ
897 mutbl:McDeclared,
898 ty:expr_ty,
899 note: NoteNone
c34b1796 900 });
62682a34 901 debug!("cat_rvalue ret {:?}", ret);
c34b1796 902 ret
223e47cc
LB
903 }
904
970d7e83 905 pub fn cat_field<N:ast_node>(&self,
1a4d82fc
JJ
906 node: &N,
907 base_cmt: cmt<'tcx>,
908 f_name: ast::Name,
909 f_ty: Ty<'tcx>)
910 -> cmt<'tcx> {
c34b1796 911 let ret = Rc::new(cmt_ {
223e47cc
LB
912 id: node.id(),
913 span: node.span(),
970d7e83 914 mutbl: base_cmt.mutbl.inherit(),
92a42be0 915 cat: Categorization::Interior(base_cmt, InteriorField(NamedField(f_name))),
1a4d82fc
JJ
916 ty: f_ty,
917 note: NoteNone
c34b1796 918 });
62682a34 919 debug!("cat_field ret {:?}", ret);
c34b1796 920 ret
223e47cc
LB
921 }
922
1a4d82fc
JJ
923 pub fn cat_tup_field<N:ast_node>(&self,
924 node: &N,
925 base_cmt: cmt<'tcx>,
c34b1796 926 f_idx: usize,
1a4d82fc
JJ
927 f_ty: Ty<'tcx>)
928 -> cmt<'tcx> {
c34b1796 929 let ret = Rc::new(cmt_ {
1a4d82fc
JJ
930 id: node.id(),
931 span: node.span(),
932 mutbl: base_cmt.mutbl.inherit(),
92a42be0 933 cat: Categorization::Interior(base_cmt, InteriorField(PositionalField(f_idx))),
1a4d82fc
JJ
934 ty: f_ty,
935 note: NoteNone
c34b1796 936 });
62682a34 937 debug!("cat_tup_field ret {:?}", ret);
c34b1796 938 ret
223e47cc
LB
939 }
940
1a4d82fc
JJ
941 fn cat_deref<N:ast_node>(&self,
942 node: &N,
943 base_cmt: cmt<'tcx>,
9e0c209e 944 deref_cnt: usize)
1a4d82fc 945 -> McResult<cmt<'tcx>> {
1a4d82fc
JJ
946 let method_call = ty::MethodCall {
947 expr_id: node.id(),
9346a6ac 948 autoderef: deref_cnt as u32
1a4d82fc 949 };
a7813a04 950 let method_ty = self.infcx.node_method_ty(method_call);
1a4d82fc
JJ
951
952 debug!("cat_deref: method_call={:?} method_ty={:?}",
62682a34 953 method_call, method_ty.map(|ty| ty));
1a4d82fc
JJ
954
955 let base_cmt = match method_ty {
956 Some(method_ty) => {
957 let ref_ty =
5bcae85e 958 self.tcx().no_late_bound_regions(&method_ty.fn_ret()).unwrap();
1a4d82fc
JJ
959 self.cat_rvalue_node(node.id(), node.span(), ref_ty)
960 }
961 None => base_cmt
962 };
963 let base_cmt_ty = base_cmt.ty;
e9174d1e 964 match base_cmt_ty.builtin_deref(true, ty::NoPreference) {
c34b1796 965 Some(mt) => {
9e0c209e 966 let ret = self.cat_deref_common(node, base_cmt, deref_cnt, mt.ty, false);
62682a34 967 debug!("cat_deref ret {:?}", ret);
9e0c209e 968 Ok(ret)
c34b1796 969 }
1a4d82fc 970 None => {
62682a34
SL
971 debug!("Explicit deref of non-derefable type: {:?}",
972 base_cmt_ty);
1a4d82fc
JJ
973 return Err(());
974 }
975 }
223e47cc
LB
976 }
977
1a4d82fc
JJ
978 fn cat_deref_common<N:ast_node>(&self,
979 node: &N,
980 base_cmt: cmt<'tcx>,
c34b1796 981 deref_cnt: usize,
1a4d82fc
JJ
982 deref_ty: Ty<'tcx>,
983 implicit: bool)
9e0c209e 984 -> cmt<'tcx>
1a4d82fc 985 {
9e0c209e 986 let ptr = match base_cmt.ty.sty {
32a655c1 987 ty::TyAdt(def, ..) if def.is_box() => Unique,
9e0c209e
SL
988 ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl),
989 ty::TyRef(r, mt) => {
990 let bk = ty::BorrowKind::from_mutbl(mt.mutbl);
991 if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) }
223e47cc 992 }
9e0c209e 993 ref ty => bug!("unexpected type in cat_deref_common: {:?}", ty)
1a4d82fc 994 };
c34b1796 995 let ret = Rc::new(cmt_ {
1a4d82fc
JJ
996 id: node.id(),
997 span: node.span(),
9e0c209e
SL
998 // For unique ptrs, we inherit mutability from the owning reference.
999 mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr),
1000 cat: Categorization::Deref(base_cmt, deref_cnt, ptr),
1a4d82fc
JJ
1001 ty: deref_ty,
1002 note: NoteNone
c34b1796 1003 });
62682a34 1004 debug!("cat_deref_common ret {:?}", ret);
9e0c209e 1005 ret
223e47cc
LB
1006 }
1007
970d7e83 1008 pub fn cat_index<N:ast_node>(&self,
1a4d82fc 1009 elt: &N,
85aaf69f
SL
1010 mut base_cmt: cmt<'tcx>,
1011 context: InteriorOffsetKind)
1a4d82fc
JJ
1012 -> McResult<cmt<'tcx>> {
1013 //! Creates a cmt for an indexing operation (`[]`).
970d7e83
LB
1014 //!
1015 //! One subtle aspect of indexing that may not be
1016 //! immediately obvious: for anything other than a fixed-length
1017 //! vector, an operation like `x[y]` actually consists of two
1018 //! disjoint (from the point of view of borrowck) operations.
1019 //! The first is a deref of `x` to create a pointer `p` that points
1020 //! at the first element in the array. The second operation is
1021 //! an index which adds `y*sizeof(T)` to `p` to obtain the
1022 //! pointer to `x[y]`. `cat_index` will produce a resulting
1023 //! cmt containing both this deref and the indexing,
1024 //! presuming that `base_cmt` is not of fixed-length type.
1025 //!
970d7e83
LB
1026 //! # Parameters
1027 //! - `elt`: the AST node being indexed
1028 //! - `base_cmt`: the cmt of `elt`
223e47cc 1029
1a4d82fc 1030 let method_call = ty::MethodCall::expr(elt.id());
a7813a04 1031 let method_ty = self.infcx.node_method_ty(method_call);
223e47cc 1032
3157f602 1033 let (element_ty, element_kind) = match method_ty {
1a4d82fc
JJ
1034 Some(method_ty) => {
1035 let ref_ty = self.overloaded_method_return_ty(method_ty);
1036 base_cmt = self.cat_rvalue_node(elt.id(), elt.span(), ref_ty);
223e47cc 1037
476ff2be 1038 (ref_ty.builtin_deref(false, ty::NoPreference).unwrap().ty,
3157f602 1039 ElementKind::OtherElement)
1a4d82fc
JJ
1040 }
1041 None => {
c1a9b12d 1042 match base_cmt.ty.builtin_index() {
3157f602 1043 Some(ty) => (ty, ElementKind::VecElement),
1a4d82fc 1044 None => {
cc61c64b 1045 debug!("Explicit index of non-indexable type {:?}", base_cmt);
1a4d82fc
JJ
1046 return Err(());
1047 }
1048 }
1049 }
223e47cc
LB
1050 };
1051
3157f602
XL
1052 let interior_elem = InteriorElement(context, element_kind);
1053 let ret =
1054 self.cat_imm_interior(elt, base_cmt.clone(), element_ty, interior_elem);
62682a34 1055 debug!("cat_index ret {:?}", ret);
c34b1796 1056 return Ok(ret);
223e47cc
LB
1057 }
1058
970d7e83 1059 pub fn cat_imm_interior<N:ast_node>(&self,
1a4d82fc
JJ
1060 node: &N,
1061 base_cmt: cmt<'tcx>,
1062 interior_ty: Ty<'tcx>,
970d7e83 1063 interior: InteriorKind)
1a4d82fc 1064 -> cmt<'tcx> {
c34b1796 1065 let ret = Rc::new(cmt_ {
970d7e83
LB
1066 id: node.id(),
1067 span: node.span(),
970d7e83 1068 mutbl: base_cmt.mutbl.inherit(),
92a42be0 1069 cat: Categorization::Interior(base_cmt, interior),
1a4d82fc
JJ
1070 ty: interior_ty,
1071 note: NoteNone
c34b1796 1072 });
62682a34 1073 debug!("cat_imm_interior ret={:?}", ret);
c34b1796 1074 ret
223e47cc
LB
1075 }
1076
970d7e83 1077 pub fn cat_downcast<N:ast_node>(&self,
1a4d82fc
JJ
1078 node: &N,
1079 base_cmt: cmt<'tcx>,
1080 downcast_ty: Ty<'tcx>,
e9174d1e 1081 variant_did: DefId)
1a4d82fc 1082 -> cmt<'tcx> {
c34b1796 1083 let ret = Rc::new(cmt_ {
970d7e83
LB
1084 id: node.id(),
1085 span: node.span(),
970d7e83 1086 mutbl: base_cmt.mutbl.inherit(),
92a42be0 1087 cat: Categorization::Downcast(base_cmt, variant_did),
1a4d82fc
JJ
1088 ty: downcast_ty,
1089 note: NoteNone
c34b1796 1090 });
62682a34 1091 debug!("cat_downcast ret={:?}", ret);
c34b1796 1092 ret
1a4d82fc
JJ
1093 }
1094
e9174d1e 1095 pub fn cat_pattern<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, mut op: F) -> McResult<()>
a7813a04 1096 where F: FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat),
1a4d82fc
JJ
1097 {
1098 self.cat_pattern_(cmt, pat, &mut op)
223e47cc
LB
1099 }
1100
1a4d82fc 1101 // FIXME(#19596) This is a workaround, but there should be a better way to do this
5bcae85e
SL
1102 fn cat_pattern_<F>(&self, cmt: cmt<'tcx>, pat: &hir::Pat, op: &mut F) -> McResult<()>
1103 where F : FnMut(&MemCategorizationContext<'a, 'gcx, 'tcx>, cmt<'tcx>, &hir::Pat)
1a4d82fc 1104 {
223e47cc
LB
1105 // Here, `cmt` is the categorization for the value being
1106 // matched and pat is the pattern it is being matched against.
1107 //
1108 // In general, the way that this works is that we walk down
1109 // the pattern, constructing a cmt that represents the path
1110 // that will be taken to reach the value being matched.
1111 //
1112 // When we encounter named bindings, we take the cmt that has
1113 // been built up and pass it off to guarantee_valid() so that
1114 // we can be sure that the binding will remain valid for the
1115 // duration of the arm.
1116 //
1a4d82fc 1117 // (*2) There is subtlety concerning the correspondence between
970d7e83
LB
1118 // pattern ids and types as compared to *expression* ids and
1119 // types. This is explained briefly. on the definition of the
1120 // type `cmt`, so go off and read what it says there, then
1121 // come back and I'll dive into a bit more detail here. :) OK,
1122 // back?
223e47cc 1123 //
970d7e83
LB
1124 // In general, the id of the cmt should be the node that
1125 // "produces" the value---patterns aren't executable code
1126 // exactly, but I consider them to "execute" when they match a
1a4d82fc
JJ
1127 // value, and I consider them to produce the value that was
1128 // matched. So if you have something like:
223e47cc
LB
1129 //
1130 // let x = @@3;
1131 // match x {
1132 // @@y { ... }
1133 // }
1134 //
970d7e83
LB
1135 // In this case, the cmt and the relevant ids would be:
1136 //
1137 // CMT Id Type of Id Type of cmt
223e47cc
LB
1138 //
1139 // local(x)->@->@
970d7e83
LB
1140 // ^~~~~~~^ `x` from discr @@int @@int
1141 // ^~~~~~~~~~^ `@@y` pattern node @@int @int
1142 // ^~~~~~~~~~~~~^ `@y` pattern node @int int
223e47cc 1143 //
970d7e83
LB
1144 // You can see that the types of the id and the cmt are in
1145 // sync in the first line, because that id is actually the id
1146 // of an expression. But once we get to pattern ids, the types
1147 // step out of sync again. So you'll see below that we always
1148 // get the type of the *subpattern* and use that.
223e47cc 1149
5bcae85e 1150 debug!("cat_pattern: {:?} cmt={:?}", pat, cmt);
1a4d82fc 1151
5bcae85e 1152 op(self, cmt.clone(), pat);
1a4d82fc 1153
7453a54e 1154 // Note: This goes up here (rather than within the PatKind::TupleStruct arm
5bcae85e 1155 // alone) because PatKind::Struct can also refer to variants.
476ff2be
SL
1156 let cmt = match pat.node {
1157 PatKind::Path(hir::QPath::Resolved(_, ref path)) |
1158 PatKind::TupleStruct(hir::QPath::Resolved(_, ref path), ..) |
1159 PatKind::Struct(hir::QPath::Resolved(_, ref path), ..) => {
1160 match path.def {
cc61c64b
XL
1161 Def::Err => {
1162 debug!("access to unresolvable pattern {:?}", pat);
1163 return Err(())
1164 }
476ff2be
SL
1165 Def::Variant(variant_did) |
1166 Def::VariantCtor(variant_did, ..) => {
1167 // univariant enums do not need downcasts
1168 let enum_did = self.tcx().parent_def_id(variant_did).unwrap();
1169 if !self.tcx().lookup_adt_def(enum_did).is_univariant() {
1170 self.cat_downcast(pat, cmt.clone(), cmt.ty, variant_did)
1171 } else {
1172 cmt
1173 }
1174 }
1175 _ => cmt
1a4d82fc 1176 }
9e0c209e 1177 }
1a4d82fc
JJ
1178 _ => cmt
1179 };
223e47cc
LB
1180
1181 match pat.node {
476ff2be
SL
1182 PatKind::TupleStruct(ref qpath, ref subpats, ddpos) => {
1183 let def = self.infcx.tables.borrow().qpath_def(qpath, pat.id);
1184 let expected_len = match def {
c30ab7b3 1185 Def::VariantCtor(def_id, CtorKind::Fn) => {
9e0c209e 1186 let enum_def = self.tcx().parent_def_id(def_id).unwrap();
5bcae85e 1187 self.tcx().lookup_adt_def(enum_def).variant_with_id(def_id).fields.len()
223e47cc 1188 }
c30ab7b3 1189 Def::StructCtor(_, CtorKind::Fn) => {
5bcae85e 1190 match self.pat_ty(&pat)?.sty {
9e0c209e 1191 ty::TyAdt(adt_def, _) => {
3157f602
XL
1192 adt_def.struct_variant().fields.len()
1193 }
1194 ref ty => {
1195 span_bug!(pat.span, "tuple struct pattern unexpected type {:?}", ty);
1196 }
223e47cc
LB
1197 }
1198 }
5bcae85e
SL
1199 def => {
1200 span_bug!(pat.span, "tuple struct pattern didn't resolve \
1201 to variant or struct {:?}", def);
223e47cc 1202 }
5bcae85e 1203 };
223e47cc 1204
5bcae85e
SL
1205 for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
1206 let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
1207 let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty,
1208 InteriorField(PositionalField(i)));
1209 self.cat_pattern_(subcmt, &subpat, op)?;
1210 }
223e47cc
LB
1211 }
1212
7453a54e 1213 PatKind::Struct(_, ref field_pats, _) => {
223e47cc 1214 // {f1: p1, ..., fN: pN}
85aaf69f 1215 for fp in field_pats {
54a0048b 1216 let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2)
b039eaaf 1217 let cmt_field = self.cat_field(pat, cmt.clone(), fp.node.name, field_ty);
54a0048b 1218 self.cat_pattern_(cmt_field, &fp.node.pat, op)?;
223e47cc
LB
1219 }
1220 }
1221
9e0c209e 1222 PatKind::Binding(.., Some(ref subpat)) => {
5bcae85e
SL
1223 self.cat_pattern_(cmt, &subpat, op)?;
1224 }
1225
3157f602 1226 PatKind::Tuple(ref subpats, ddpos) => {
223e47cc 1227 // (p1, ..., pN)
3157f602 1228 let expected_len = match self.pat_ty(&pat)?.sty {
8bb4bdeb 1229 ty::TyTuple(ref tys, _) => tys.len(),
3157f602
XL
1230 ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty),
1231 };
1232 for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) {
54a0048b 1233 let subpat_ty = self.pat_ty(&subpat)?; // see (*2)
5bcae85e
SL
1234 let subcmt = self.cat_imm_interior(pat, cmt.clone(), subpat_ty,
1235 InteriorField(PositionalField(i)));
54a0048b 1236 self.cat_pattern_(subcmt, &subpat, op)?;
223e47cc
LB
1237 }
1238 }
1239
7453a54e 1240 PatKind::Box(ref subpat) | PatKind::Ref(ref subpat, _) => {
1a4d82fc 1241 // box p1, &p1, &mut p1. we can ignore the mutability of
7453a54e 1242 // PatKind::Ref since that information is already contained
1a4d82fc 1243 // in the type.
9e0c209e 1244 let subcmt = self.cat_deref(pat, cmt, 0)?;
5bcae85e 1245 self.cat_pattern_(subcmt, &subpat, op)?;
223e47cc
LB
1246 }
1247
c30ab7b3 1248 PatKind::Slice(ref before, ref slice, ref after) => {
5bcae85e
SL
1249 let context = InteriorOffsetKind::Pattern;
1250 let elt_cmt = self.cat_index(pat, cmt, context)?;
1251 for before_pat in before {
1252 self.cat_pattern_(elt_cmt.clone(), &before_pat, op)?;
1253 }
1254 if let Some(ref slice_pat) = *slice {
1255 self.cat_pattern_(elt_cmt.clone(), &slice_pat, op)?;
1256 }
1257 for after_pat in after {
1258 self.cat_pattern_(elt_cmt.clone(), &after_pat, op)?;
1259 }
223e47cc
LB
1260 }
1261
476ff2be 1262 PatKind::Path(_) | PatKind::Binding(.., None) |
5bcae85e
SL
1263 PatKind::Lit(..) | PatKind::Range(..) | PatKind::Wild => {
1264 // always ok
223e47cc 1265 }
223e47cc 1266 }
223e47cc 1267
1a4d82fc 1268 Ok(())
223e47cc 1269 }
223e47cc 1270
1a4d82fc
JJ
1271 fn overloaded_method_return_ty(&self,
1272 method_ty: Ty<'tcx>)
1273 -> Ty<'tcx>
1274 {
1275 // When we process an overloaded `*` or `[]` etc, we often
1276 // need to extract the return type of the method. These method
1277 // types are generated by method resolution and always have
1278 // all late-bound regions fully instantiated, so we just want
1279 // to skip past the binder.
c1a9b12d 1280 self.tcx().no_late_bound_regions(&method_ty.fn_ret())
85aaf69f 1281 .unwrap()
223e47cc 1282 }
1a4d82fc 1283}
223e47cc 1284
c34b1796
AL
1285#[derive(Clone, Debug)]
1286pub enum Aliasability {
1287 FreelyAliasable(AliasableReason),
1288 NonAliasable,
1289 ImmutableUnique(Box<Aliasability>),
1290}
1291
1292#[derive(Copy, Clone, Debug)]
970d7e83 1293pub enum AliasableReason {
1a4d82fc 1294 AliasableBorrowed,
62682a34
SL
1295 AliasableStatic,
1296 AliasableStaticMut,
970d7e83
LB
1297}
1298
1a4d82fc
JJ
1299impl<'tcx> cmt_<'tcx> {
1300 pub fn guarantor(&self) -> cmt<'tcx> {
62682a34 1301 //! Returns `self` after stripping away any derefs or
970d7e83
LB
1302 //! interior content. The return value is basically the `cmt` which
1303 //! determines how long the value in `self` remains live.
1304
1305 match self.cat {
92a42be0
SL
1306 Categorization::Rvalue(..) |
1307 Categorization::StaticItem |
1308 Categorization::Local(..) |
9e0c209e
SL
1309 Categorization::Deref(.., UnsafePtr(..)) |
1310 Categorization::Deref(.., BorrowedPtr(..)) |
1311 Categorization::Deref(.., Implicit(..)) |
92a42be0 1312 Categorization::Upvar(..) => {
1a4d82fc 1313 Rc::new((*self).clone())
970d7e83 1314 }
92a42be0
SL
1315 Categorization::Downcast(ref b, _) |
1316 Categorization::Interior(ref b, _) |
1317 Categorization::Deref(ref b, _, Unique) => {
970d7e83
LB
1318 b.guarantor()
1319 }
1320 }
1321 }
1322
c34b1796 1323 /// Returns `FreelyAliasable(_)` if this lvalue represents a freely aliasable pointer type.
a7813a04 1324 pub fn freely_aliasable(&self) -> Aliasability {
970d7e83
LB
1325 // Maybe non-obvious: copied upvars can only be considered
1326 // non-aliasable in once closures, since any other kind can be
1327 // aliased and eventually recused.
1328
1329 match self.cat {
92a42be0
SL
1330 Categorization::Deref(ref b, _, BorrowedPtr(ty::MutBorrow, _)) |
1331 Categorization::Deref(ref b, _, Implicit(ty::MutBorrow, _)) |
1332 Categorization::Deref(ref b, _, BorrowedPtr(ty::UniqueImmBorrow, _)) |
1333 Categorization::Deref(ref b, _, Implicit(ty::UniqueImmBorrow, _)) |
cc61c64b 1334 Categorization::Deref(ref b, _, Unique) |
92a42be0
SL
1335 Categorization::Downcast(ref b, _) |
1336 Categorization::Interior(ref b, _) => {
1a4d82fc 1337 // Aliasability depends on base cmt
a7813a04 1338 b.freely_aliasable()
1a4d82fc
JJ
1339 }
1340
92a42be0
SL
1341 Categorization::Rvalue(..) |
1342 Categorization::Local(..) |
1343 Categorization::Upvar(..) |
9e0c209e 1344 Categorization::Deref(.., UnsafePtr(..)) => { // yes, it's aliasable, but...
c34b1796 1345 NonAliasable
223e47cc 1346 }
970d7e83 1347
92a42be0 1348 Categorization::StaticItem => {
1a4d82fc 1349 if self.mutbl.is_mutable() {
62682a34 1350 FreelyAliasable(AliasableStaticMut)
1a4d82fc 1351 } else {
62682a34 1352 FreelyAliasable(AliasableStatic)
1a4d82fc 1353 }
223e47cc 1354 }
970d7e83 1355
cc61c64b
XL
1356 Categorization::Deref(_, _, BorrowedPtr(ty::ImmBorrow, _)) |
1357 Categorization::Deref(_, _, Implicit(ty::ImmBorrow, _)) => {
1358 FreelyAliasable(AliasableBorrowed)
970d7e83 1359 }
1a4d82fc
JJ
1360 }
1361 }
970d7e83 1362
1a4d82fc
JJ
1363 // Digs down through one or two layers of deref and grabs the cmt
1364 // for the upvar if a note indicates there is one.
1365 pub fn upvar(&self) -> Option<cmt<'tcx>> {
1366 match self.note {
1367 NoteClosureEnv(..) | NoteUpvarRef(..) => {
1368 Some(match self.cat {
9e0c209e 1369 Categorization::Deref(ref inner, ..) => {
1a4d82fc 1370 match inner.cat {
9e0c209e 1371 Categorization::Deref(ref inner, ..) => inner.clone(),
92a42be0 1372 Categorization::Upvar(..) => inner.clone(),
54a0048b 1373 _ => bug!()
1a4d82fc
JJ
1374 }
1375 }
54a0048b 1376 _ => bug!()
1a4d82fc 1377 })
970d7e83 1378 }
1a4d82fc
JJ
1379 NoteNone => None
1380 }
1381 }
970d7e83 1382
1a4d82fc 1383
a7813a04 1384 pub fn descriptive_string(&self, tcx: TyCtxt) -> String {
1a4d82fc 1385 match self.cat {
92a42be0 1386 Categorization::StaticItem => {
1a4d82fc
JJ
1387 "static item".to_string()
1388 }
92a42be0 1389 Categorization::Rvalue(..) => {
1a4d82fc
JJ
1390 "non-lvalue".to_string()
1391 }
92a42be0 1392 Categorization::Local(vid) => {
32a655c1 1393 if tcx.hir.is_argument(vid) {
b039eaaf
SL
1394 "argument".to_string()
1395 } else {
1396 "local variable".to_string()
1a4d82fc
JJ
1397 }
1398 }
9e0c209e 1399 Categorization::Deref(.., pk) => {
1a4d82fc
JJ
1400 let upvar = self.upvar();
1401 match upvar.as_ref().map(|i| &i.cat) {
92a42be0 1402 Some(&Categorization::Upvar(ref var)) => {
62682a34 1403 var.to_string()
1a4d82fc 1404 }
54a0048b 1405 Some(_) => bug!(),
1a4d82fc
JJ
1406 None => {
1407 match pk {
1408 Implicit(..) => {
1409 format!("indexed content")
1410 }
1411 Unique => {
1412 format!("`Box` content")
1413 }
1414 UnsafePtr(..) => {
62682a34 1415 format!("dereference of raw pointer")
1a4d82fc
JJ
1416 }
1417 BorrowedPtr(..) => {
1418 format!("borrowed content")
1419 }
1420 }
1421 }
1422 }
1423 }
92a42be0 1424 Categorization::Interior(_, InteriorField(NamedField(_))) => {
1a4d82fc
JJ
1425 "field".to_string()
1426 }
92a42be0 1427 Categorization::Interior(_, InteriorField(PositionalField(_))) => {
1a4d82fc
JJ
1428 "anonymous field".to_string()
1429 }
92a42be0
SL
1430 Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
1431 VecElement)) |
1432 Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Index,
1433 OtherElement)) => {
1a4d82fc
JJ
1434 "indexed content".to_string()
1435 }
92a42be0
SL
1436 Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
1437 VecElement)) |
1438 Categorization::Interior(_, InteriorElement(InteriorOffsetKind::Pattern,
1439 OtherElement)) => {
85aaf69f
SL
1440 "pattern-bound indexed content".to_string()
1441 }
92a42be0 1442 Categorization::Upvar(ref var) => {
62682a34 1443 var.to_string()
1a4d82fc 1444 }
92a42be0 1445 Categorization::Downcast(ref cmt, _) => {
1a4d82fc 1446 cmt.descriptive_string(tcx)
970d7e83
LB
1447 }
1448 }
1449 }
1450}
1451
62682a34
SL
1452impl<'tcx> fmt::Debug for cmt_<'tcx> {
1453 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1454 write!(f, "{{{:?} id:{} m:{:?} ty:{:?}}}",
1455 self.cat,
1456 self.id,
1457 self.mutbl,
1458 self.ty)
970d7e83
LB
1459 }
1460}
1461
92a42be0 1462impl<'tcx> fmt::Debug for Categorization<'tcx> {
62682a34 1463 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
970d7e83 1464 match *self {
92a42be0 1465 Categorization::StaticItem => write!(f, "static"),
32a655c1
SL
1466 Categorization::Rvalue(r, or) => {
1467 write!(f, "rvalue({:?}, {:?})", r, or)
1468 }
92a42be0 1469 Categorization::Local(id) => {
c1a9b12d 1470 let name = ty::tls::with(|tcx| tcx.local_var_name_str(id));
62682a34
SL
1471 write!(f, "local({})", name)
1472 }
92a42be0 1473 Categorization::Upvar(upvar) => {
62682a34 1474 write!(f, "upvar({:?})", upvar)
970d7e83 1475 }
92a42be0 1476 Categorization::Deref(ref cmt, derefs, ptr) => {
62682a34 1477 write!(f, "{:?}-{:?}{}->", cmt.cat, ptr, derefs)
970d7e83 1478 }
92a42be0 1479 Categorization::Interior(ref cmt, interior) => {
62682a34 1480 write!(f, "{:?}.{:?}", cmt.cat, interior)
1a4d82fc 1481 }
92a42be0 1482 Categorization::Downcast(ref cmt, _) => {
62682a34 1483 write!(f, "{:?}->(enum)", cmt.cat)
223e47cc
LB
1484 }
1485 }
1486 }
970d7e83
LB
1487}
1488
1a4d82fc 1489pub fn ptr_sigil(ptr: PointerKind) -> &'static str {
970d7e83 1490 match ptr {
1a4d82fc
JJ
1491 Unique => "Box",
1492 BorrowedPtr(ty::ImmBorrow, _) |
1493 Implicit(ty::ImmBorrow, _) => "&",
1494 BorrowedPtr(ty::MutBorrow, _) |
1495 Implicit(ty::MutBorrow, _) => "&mut",
1496 BorrowedPtr(ty::UniqueImmBorrow, _) |
1497 Implicit(ty::UniqueImmBorrow, _) => "&unique",
1498 UnsafePtr(_) => "*",
970d7e83
LB
1499 }
1500}
223e47cc 1501
9e0c209e 1502impl<'tcx> fmt::Debug for PointerKind<'tcx> {
62682a34 1503 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
223e47cc 1504 match *self {
62682a34 1505 Unique => write!(f, "Box"),
1a4d82fc
JJ
1506 BorrowedPtr(ty::ImmBorrow, ref r) |
1507 Implicit(ty::ImmBorrow, ref r) => {
62682a34 1508 write!(f, "&{:?}", r)
1a4d82fc
JJ
1509 }
1510 BorrowedPtr(ty::MutBorrow, ref r) |
1511 Implicit(ty::MutBorrow, ref r) => {
62682a34 1512 write!(f, "&{:?} mut", r)
1a4d82fc
JJ
1513 }
1514 BorrowedPtr(ty::UniqueImmBorrow, ref r) |
1515 Implicit(ty::UniqueImmBorrow, ref r) => {
62682a34 1516 write!(f, "&{:?} uniq", r)
1a4d82fc 1517 }
62682a34 1518 UnsafePtr(_) => write!(f, "*")
223e47cc
LB
1519 }
1520 }
1521}
1522
62682a34
SL
1523impl fmt::Debug for InteriorKind {
1524 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1a4d82fc 1525 match *self {
62682a34
SL
1526 InteriorField(NamedField(fld)) => write!(f, "{}", fld),
1527 InteriorField(PositionalField(i)) => write!(f, "#{}", i),
1528 InteriorElement(..) => write!(f, "[]"),
1a4d82fc
JJ
1529 }
1530 }
1531}
1532
62682a34
SL
1533impl fmt::Debug for Upvar {
1534 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1535 write!(f, "{:?}/{:?}", self.id, self.kind)
1a4d82fc
JJ
1536 }
1537}
1538
62682a34
SL
1539impl fmt::Display for Upvar {
1540 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1a4d82fc 1541 let kind = match self.kind {
54a0048b
SL
1542 ty::ClosureKind::Fn => "Fn",
1543 ty::ClosureKind::FnMut => "FnMut",
1544 ty::ClosureKind::FnOnce => "FnOnce",
1a4d82fc 1545 };
62682a34 1546 write!(f, "captured outer variable in an `{}` closure", kind)
1a4d82fc
JJ
1547 }
1548}