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