]>
Commit | Line | Data |
---|---|---|
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 | ||
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::*; | |
1a4d82fc JJ |
68 | pub use self::AliasableReason::*; |
69 | pub use self::Note::*; | |
1a4d82fc | 70 | |
c34b1796 AL |
71 | use self::Aliasability::*; |
72 | ||
54a0048b | 73 | use hir::def_id::DefId; |
32a655c1 | 74 | use hir::map as hir_map; |
a7813a04 | 75 | use infer::InferCtxt; |
c30ab7b3 | 76 | use hir::def::{Def, CtorKind}; |
54a0048b SL |
77 | use ty::adjustment; |
78 | use ty::{self, Ty, TyCtxt}; | |
1a4d82fc | 79 | |
54a0048b | 80 | use hir::{MutImmutable, MutMutable, PatKind}; |
3157f602 | 81 | use hir::pat_util::EnumerateAndAdjustIterator; |
54a0048b | 82 | use hir; |
223e47cc | 83 | use syntax::ast; |
3157f602 | 84 | use syntax_pos::Span; |
223e47cc | 85 | |
62682a34 | 86 | use std::fmt; |
1a4d82fc JJ |
87 | use std::rc::Rc; |
88 | ||
62682a34 | 89 | #[derive(Clone, PartialEq)] |
92a42be0 | 90 | pub 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 |
105 | pub 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 | 112 | pub 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 |
129 | pub enum InteriorKind { |
130 | InteriorField(FieldName), | |
85aaf69f | 131 | InteriorElement(InteriorOffsetKind, ElementKind), |
223e47cc LB |
132 | } |
133 | ||
85aaf69f | 134 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
970d7e83 | 135 | pub 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)] |
141 | pub 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 |
147 | pub enum ElementKind { |
148 | VecElement, | |
970d7e83 LB |
149 | OtherElement, |
150 | } | |
151 | ||
85aaf69f | 152 | #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] |
223e47cc LB |
153 | pub 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 |
165 | pub 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 |
186 | pub struct cmt_<'tcx> { |
187 | pub id: ast::NodeId, // id of expr/pat producing this value | |
188 | pub span: Span, // span of same expr/pat | |
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 | 195 | pub type cmt<'tcx> = Rc<cmt_<'tcx>>; |
223e47cc | 196 | |
cc61c64b XL |
197 | pub 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 |
204 | impl<'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 |
274 | pub trait ast_node { |
275 | fn id(&self) -> ast::NodeId; | |
276 | fn span(&self) -> Span; | |
223e47cc LB |
277 | } |
278 | ||
e9174d1e | 279 | impl 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 | 284 | impl 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 |
290 | pub 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)] | |
296 | pub 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 | |
306 | pub type McResult<T> = Result<T, ()>; | |
307 | ||
1a4d82fc | 308 | impl 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 |
404 | impl<'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)] |
1286 | pub enum Aliasability { | |
1287 | FreelyAliasable(AliasableReason), | |
1288 | NonAliasable, | |
1289 | ImmutableUnique(Box<Aliasability>), | |
1290 | } | |
1291 | ||
1292 | #[derive(Copy, Clone, Debug)] | |
970d7e83 | 1293 | pub enum AliasableReason { |
1a4d82fc | 1294 | AliasableBorrowed, |
62682a34 SL |
1295 | AliasableStatic, |
1296 | AliasableStaticMut, | |
970d7e83 LB |
1297 | } |
1298 | ||
1a4d82fc JJ |
1299 | impl<'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 |
1452 | impl<'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 | 1462 | impl<'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 | 1489 | pub 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 | 1502 | impl<'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 |
1523 | impl 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 |
1533 | impl 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 |
1539 | impl 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 | } |