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