]>
Commit | Line | Data |
---|---|---|
e9174d1e SL |
1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
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 | ||
7453a54e | 11 | use graphviz::IntoCow; |
54a0048b SL |
12 | use middle::const_val::ConstVal; |
13 | use rustc_const_math::{ConstUsize, ConstInt}; | |
14 | use hir::def_id::DefId; | |
15 | use ty::subst::Substs; | |
16 | use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; | |
17 | use util::ppaux; | |
b039eaaf | 18 | use rustc_back::slice; |
54a0048b | 19 | use hir::InlineAsm; |
9cc50fc6 | 20 | use std::ascii; |
7453a54e | 21 | use std::borrow::{Cow}; |
9cc50fc6 SL |
22 | use std::fmt::{self, Debug, Formatter, Write}; |
23 | use std::{iter, u32}; | |
24 | use std::ops::{Index, IndexMut}; | |
7453a54e SL |
25 | use syntax::ast::{self, Name}; |
26 | use syntax::codemap::Span; | |
e9174d1e SL |
27 | |
28 | /// Lowered representation of a single function. | |
7453a54e | 29 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
b039eaaf | 30 | pub struct Mir<'tcx> { |
92a42be0 SL |
31 | /// List of basic blocks. References to basic block use a newtyped index type `BasicBlock` |
32 | /// that indexes into this vector. | |
b039eaaf | 33 | pub basic_blocks: Vec<BasicBlockData<'tcx>>, |
e9174d1e | 34 | |
54a0048b SL |
35 | /// List of lexical scopes; these are referenced by statements and |
36 | /// used (eventually) for debuginfo. Indexed by a `ScopeId`. | |
37 | pub scopes: Vec<ScopeData>, | |
38 | ||
92a42be0 SL |
39 | /// Return type of the function. |
40 | pub return_ty: FnOutput<'tcx>, | |
e9174d1e | 41 | |
92a42be0 SL |
42 | /// Variables: these are stack slots corresponding to user variables. They may be |
43 | /// assigned many times. | |
b039eaaf | 44 | pub var_decls: Vec<VarDecl<'tcx>>, |
92a42be0 SL |
45 | |
46 | /// Args: these are stack slots corresponding to the input arguments. | |
b039eaaf | 47 | pub arg_decls: Vec<ArgDecl<'tcx>>, |
92a42be0 SL |
48 | |
49 | /// Temp declarations: stack slots that for temporaries created by | |
50 | /// the compiler. These are assigned once, but they are not SSA | |
51 | /// values in that it is possible to borrow them and mutate them | |
52 | /// through the resulting reference. | |
b039eaaf | 53 | pub temp_decls: Vec<TempDecl<'tcx>>, |
7453a54e SL |
54 | |
55 | /// A span representing this MIR, for error reporting | |
56 | pub span: Span, | |
e9174d1e SL |
57 | } |
58 | ||
59 | /// where execution begins | |
60 | pub const START_BLOCK: BasicBlock = BasicBlock(0); | |
61 | ||
62 | /// where execution ends, on normal return | |
63 | pub const END_BLOCK: BasicBlock = BasicBlock(1); | |
64 | ||
b039eaaf | 65 | impl<'tcx> Mir<'tcx> { |
e9174d1e SL |
66 | pub fn all_basic_blocks(&self) -> Vec<BasicBlock> { |
67 | (0..self.basic_blocks.len()) | |
68 | .map(|i| BasicBlock::new(i)) | |
69 | .collect() | |
70 | } | |
71 | ||
b039eaaf | 72 | pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> { |
e9174d1e SL |
73 | &self.basic_blocks[bb.index()] |
74 | } | |
75 | ||
b039eaaf | 76 | pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> { |
e9174d1e SL |
77 | &mut self.basic_blocks[bb.index()] |
78 | } | |
79 | } | |
80 | ||
9cc50fc6 SL |
81 | impl<'tcx> Index<BasicBlock> for Mir<'tcx> { |
82 | type Output = BasicBlockData<'tcx>; | |
83 | ||
84 | #[inline] | |
85 | fn index(&self, index: BasicBlock) -> &BasicBlockData<'tcx> { | |
86 | self.basic_block_data(index) | |
87 | } | |
88 | } | |
89 | ||
90 | impl<'tcx> IndexMut<BasicBlock> for Mir<'tcx> { | |
91 | #[inline] | |
92 | fn index_mut(&mut self, index: BasicBlock) -> &mut BasicBlockData<'tcx> { | |
93 | self.basic_block_data_mut(index) | |
94 | } | |
95 | } | |
96 | ||
e9174d1e SL |
97 | /////////////////////////////////////////////////////////////////////////// |
98 | // Mutability and borrow kinds | |
99 | ||
9cc50fc6 | 100 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
101 | pub enum Mutability { |
102 | Mut, | |
103 | Not, | |
104 | } | |
105 | ||
9cc50fc6 | 106 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
107 | pub enum BorrowKind { |
108 | /// Data must be immutable and is aliasable. | |
109 | Shared, | |
110 | ||
111 | /// Data must be immutable but not aliasable. This kind of borrow | |
112 | /// cannot currently be expressed by the user and is used only in | |
113 | /// implicit closure bindings. It is needed when you the closure | |
114 | /// is borrowing or mutating a mutable referent, e.g.: | |
115 | /// | |
116 | /// let x: &mut isize = ...; | |
117 | /// let y = || *x += 5; | |
118 | /// | |
119 | /// If we were to try to translate this closure into a more explicit | |
120 | /// form, we'd encounter an error with the code as written: | |
121 | /// | |
122 | /// struct Env { x: & &mut isize } | |
123 | /// let x: &mut isize = ...; | |
124 | /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn | |
125 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
126 | /// | |
127 | /// This is then illegal because you cannot mutate a `&mut` found | |
128 | /// in an aliasable location. To solve, you'd have to translate with | |
129 | /// an `&mut` borrow: | |
130 | /// | |
131 | /// struct Env { x: & &mut isize } | |
132 | /// let x: &mut isize = ...; | |
133 | /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x | |
134 | /// fn fn_ptr(env: &mut Env) { **env.x += 5; } | |
135 | /// | |
136 | /// Now the assignment to `**env.x` is legal, but creating a | |
137 | /// mutable pointer to `x` is not because `x` is not mutable. We | |
138 | /// could fix this by declaring `x` as `let mut x`. This is ok in | |
139 | /// user code, if awkward, but extra weird for closures, since the | |
140 | /// borrow is hidden. | |
141 | /// | |
142 | /// So we introduce a "unique imm" borrow -- the referent is | |
143 | /// immutable, but not aliasable. This solves the problem. For | |
144 | /// simplicity, we don't give users the way to express this | |
145 | /// borrow, it's just used when translating closures. | |
146 | Unique, | |
147 | ||
148 | /// Data is mutable and not aliasable. | |
b039eaaf | 149 | Mut, |
e9174d1e SL |
150 | } |
151 | ||
152 | /////////////////////////////////////////////////////////////////////////// | |
153 | // Variables and temps | |
154 | ||
7453a54e SL |
155 | /// A "variable" is a binding declared by the user as part of the fn |
156 | /// decl, a let, etc. | |
157 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
b039eaaf | 158 | pub struct VarDecl<'tcx> { |
54a0048b | 159 | /// `let mut x` vs `let x` |
e9174d1e | 160 | pub mutability: Mutability, |
54a0048b SL |
161 | |
162 | /// name that user gave the variable; not that, internally, | |
163 | /// mir references variables by index | |
b039eaaf | 164 | pub name: Name, |
54a0048b SL |
165 | |
166 | /// type inferred for this variable (`let x: ty = ...`) | |
b039eaaf | 167 | pub ty: Ty<'tcx>, |
54a0048b SL |
168 | |
169 | /// scope in which variable was declared | |
170 | pub scope: ScopeId, | |
171 | ||
172 | /// span where variable was declared | |
173 | pub span: Span, | |
e9174d1e SL |
174 | } |
175 | ||
7453a54e SL |
176 | /// A "temp" is a temporary that we place on the stack. They are |
177 | /// anonymous, always mutable, and have only a type. | |
178 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
b039eaaf SL |
179 | pub struct TempDecl<'tcx> { |
180 | pub ty: Ty<'tcx>, | |
e9174d1e SL |
181 | } |
182 | ||
7453a54e SL |
183 | /// A "arg" is one of the function's formal arguments. These are |
184 | /// anonymous and distinct from the bindings that the user declares. | |
185 | /// | |
186 | /// For example, in this function: | |
187 | /// | |
188 | /// ``` | |
189 | /// fn foo((x, y): (i32, u32)) { ... } | |
190 | /// ``` | |
191 | /// | |
192 | /// there is only one argument, of type `(i32, u32)`, but two bindings | |
193 | /// (`x` and `y`). | |
194 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
b039eaaf SL |
195 | pub struct ArgDecl<'tcx> { |
196 | pub ty: Ty<'tcx>, | |
54a0048b SL |
197 | |
198 | /// If true, this argument is a tuple after monomorphization, | |
199 | /// and has to be collected from multiple actual arguments. | |
200 | pub spread: bool | |
e9174d1e SL |
201 | } |
202 | ||
e9174d1e SL |
203 | /////////////////////////////////////////////////////////////////////////// |
204 | // BasicBlock | |
205 | ||
206 | /// The index of a particular basic block. The index is into the `basic_blocks` | |
207 | /// list of the `Mir`. | |
208 | /// | |
209 | /// (We use a `u32` internally just to save memory.) | |
54a0048b | 210 | #[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
211 | pub struct BasicBlock(u32); |
212 | ||
213 | impl BasicBlock { | |
214 | pub fn new(index: usize) -> BasicBlock { | |
215 | assert!(index < (u32::MAX as usize)); | |
216 | BasicBlock(index as u32) | |
217 | } | |
218 | ||
219 | /// Extract the index. | |
220 | pub fn index(self) -> usize { | |
221 | self.0 as usize | |
222 | } | |
223 | } | |
224 | ||
225 | impl Debug for BasicBlock { | |
9cc50fc6 SL |
226 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
227 | write!(fmt, "bb{}", self.0) | |
e9174d1e SL |
228 | } |
229 | } | |
230 | ||
231 | /////////////////////////////////////////////////////////////////////////// | |
54a0048b | 232 | // BasicBlockData and Terminator |
e9174d1e | 233 | |
7453a54e | 234 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
b039eaaf | 235 | pub struct BasicBlockData<'tcx> { |
54a0048b | 236 | /// List of statements in this block. |
b039eaaf | 237 | pub statements: Vec<Statement<'tcx>>, |
54a0048b SL |
238 | |
239 | /// Terminator for this block. | |
240 | /// | |
241 | /// NB. This should generally ONLY be `None` during construction. | |
242 | /// Therefore, you should generally access it via the | |
243 | /// `terminator()` or `terminator_mut()` methods. The only | |
244 | /// exception is that certain passes, such as `simplify_cfg`, swap | |
245 | /// out the terminator temporarily with `None` while they continue | |
246 | /// to recurse over the set of basic blocks. | |
9cc50fc6 | 247 | pub terminator: Option<Terminator<'tcx>>, |
54a0048b SL |
248 | |
249 | /// If true, this block lies on an unwind path. This is used | |
250 | /// during trans where distinct kinds of basic blocks may be | |
251 | /// generated (particularly for MSVC cleanup). Unwind blocks must | |
252 | /// only branch to other unwind blocks. | |
9cc50fc6 | 253 | pub is_cleanup: bool, |
e9174d1e SL |
254 | } |
255 | ||
54a0048b SL |
256 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
257 | pub struct Terminator<'tcx> { | |
258 | pub span: Span, | |
259 | pub scope: ScopeId, | |
260 | pub kind: TerminatorKind<'tcx> | |
261 | } | |
262 | ||
7453a54e | 263 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
54a0048b | 264 | pub enum TerminatorKind<'tcx> { |
e9174d1e | 265 | /// block should have one successor in the graph; we jump there |
b039eaaf SL |
266 | Goto { |
267 | target: BasicBlock, | |
268 | }, | |
e9174d1e | 269 | |
e9174d1e | 270 | /// jump to branch 0 if this lvalue evaluates to true |
b039eaaf SL |
271 | If { |
272 | cond: Operand<'tcx>, | |
9cc50fc6 | 273 | targets: (BasicBlock, BasicBlock), |
b039eaaf | 274 | }, |
e9174d1e SL |
275 | |
276 | /// lvalue evaluates to some enum; jump depending on the branch | |
b039eaaf SL |
277 | Switch { |
278 | discr: Lvalue<'tcx>, | |
92a42be0 SL |
279 | adt_def: AdtDef<'tcx>, |
280 | targets: Vec<BasicBlock>, | |
281 | }, | |
282 | ||
283 | /// operand evaluates to an integer; jump depending on its value | |
284 | /// to one of the targets, and otherwise fallback to `otherwise` | |
285 | SwitchInt { | |
286 | /// discriminant value being tested | |
287 | discr: Lvalue<'tcx>, | |
288 | ||
289 | /// type of value being tested | |
290 | switch_ty: Ty<'tcx>, | |
291 | ||
292 | /// Possible values. The locations to branch to in each case | |
293 | /// are found in the corresponding indices from the `targets` vector. | |
294 | values: Vec<ConstVal>, | |
295 | ||
296 | /// Possible branch sites. The length of this vector should be | |
297 | /// equal to the length of the `values` vector plus 1 -- the | |
298 | /// extra item is the block to branch to if none of the values | |
299 | /// fit. | |
b039eaaf SL |
300 | targets: Vec<BasicBlock>, |
301 | }, | |
e9174d1e | 302 | |
9cc50fc6 SL |
303 | /// Indicates that the landing pad is finished and unwinding should |
304 | /// continue. Emitted by build::scope::diverge_cleanup. | |
305 | Resume, | |
e9174d1e SL |
306 | |
307 | /// Indicates a normal return. The ReturnPointer lvalue should | |
308 | /// have been filled in by now. This should only occur in the | |
309 | /// `END_BLOCK`. | |
310 | Return, | |
311 | ||
7453a54e SL |
312 | /// Drop the Lvalue |
313 | Drop { | |
314 | value: Lvalue<'tcx>, | |
315 | target: BasicBlock, | |
316 | unwind: Option<BasicBlock> | |
317 | }, | |
318 | ||
9cc50fc6 | 319 | /// Block ends with a call of a converging function |
b039eaaf | 320 | Call { |
9cc50fc6 SL |
321 | /// The function that’s being called |
322 | func: Operand<'tcx>, | |
323 | /// Arguments the function is called with | |
324 | args: Vec<Operand<'tcx>>, | |
7453a54e SL |
325 | /// Destination for the return value. If some, the call is converging. |
326 | destination: Option<(Lvalue<'tcx>, BasicBlock)>, | |
327 | /// Cleanups to be done if the call unwinds. | |
328 | cleanup: Option<BasicBlock> | |
b039eaaf | 329 | }, |
e9174d1e SL |
330 | } |
331 | ||
b039eaaf | 332 | impl<'tcx> Terminator<'tcx> { |
7453a54e | 333 | pub fn successors(&self) -> Cow<[BasicBlock]> { |
54a0048b SL |
334 | self.kind.successors() |
335 | } | |
336 | ||
337 | pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> { | |
338 | self.kind.successors_mut() | |
339 | } | |
340 | } | |
341 | ||
342 | impl<'tcx> TerminatorKind<'tcx> { | |
343 | pub fn successors(&self) -> Cow<[BasicBlock]> { | |
344 | use self::TerminatorKind::*; | |
e9174d1e | 345 | match *self { |
7453a54e SL |
346 | Goto { target: ref b } => slice::ref_slice(b).into_cow(), |
347 | If { targets: (b1, b2), .. } => vec![b1, b2].into_cow(), | |
348 | Switch { targets: ref b, .. } => b[..].into_cow(), | |
349 | SwitchInt { targets: ref b, .. } => b[..].into_cow(), | |
350 | Resume => (&[]).into_cow(), | |
351 | Return => (&[]).into_cow(), | |
352 | Call { destination: Some((_, t)), cleanup: Some(c), .. } => vec![t, c].into_cow(), | |
353 | Call { destination: Some((_, ref t)), cleanup: None, .. } => | |
354 | slice::ref_slice(t).into_cow(), | |
355 | Call { destination: None, cleanup: Some(ref c), .. } => slice::ref_slice(c).into_cow(), | |
356 | Call { destination: None, cleanup: None, .. } => (&[]).into_cow(), | |
357 | Drop { target, unwind: Some(unwind), .. } => vec![target, unwind].into_cow(), | |
358 | Drop { ref target, .. } => slice::ref_slice(target).into_cow(), | |
e9174d1e SL |
359 | } |
360 | } | |
92a42be0 | 361 | |
7453a54e SL |
362 | // FIXME: no mootable cow. I’m honestly not sure what a “cow” between `&mut [BasicBlock]` and |
363 | // `Vec<&mut BasicBlock>` would look like in the first place. | |
364 | pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> { | |
54a0048b | 365 | use self::TerminatorKind::*; |
92a42be0 | 366 | match *self { |
7453a54e SL |
367 | Goto { target: ref mut b } => vec![b], |
368 | If { targets: (ref mut b1, ref mut b2), .. } => vec![b1, b2], | |
369 | Switch { targets: ref mut b, .. } => b.iter_mut().collect(), | |
370 | SwitchInt { targets: ref mut b, .. } => b.iter_mut().collect(), | |
371 | Resume => Vec::new(), | |
372 | Return => Vec::new(), | |
373 | Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut c), .. } => vec![t, c], | |
374 | Call { destination: Some((_, ref mut t)), cleanup: None, .. } => vec![t], | |
375 | Call { destination: None, cleanup: Some(ref mut c), .. } => vec![c], | |
376 | Call { destination: None, cleanup: None, .. } => vec![], | |
377 | Drop { ref mut target, unwind: Some(ref mut unwind), .. } => vec![target, unwind], | |
378 | Drop { ref mut target, .. } => vec![target] | |
92a42be0 SL |
379 | } |
380 | } | |
e9174d1e SL |
381 | } |
382 | ||
b039eaaf | 383 | impl<'tcx> BasicBlockData<'tcx> { |
9cc50fc6 | 384 | pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> { |
e9174d1e SL |
385 | BasicBlockData { |
386 | statements: vec![], | |
387 | terminator: terminator, | |
9cc50fc6 | 388 | is_cleanup: false, |
e9174d1e SL |
389 | } |
390 | } | |
9cc50fc6 SL |
391 | |
392 | /// Accessor for terminator. | |
393 | /// | |
394 | /// Terminator may not be None after construction of the basic block is complete. This accessor | |
395 | /// provides a convenience way to reach the terminator. | |
396 | pub fn terminator(&self) -> &Terminator<'tcx> { | |
397 | self.terminator.as_ref().expect("invalid terminator state") | |
398 | } | |
399 | ||
400 | pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { | |
401 | self.terminator.as_mut().expect("invalid terminator state") | |
402 | } | |
e9174d1e SL |
403 | } |
404 | ||
54a0048b | 405 | impl<'tcx> Debug for TerminatorKind<'tcx> { |
9cc50fc6 | 406 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
54a0048b | 407 | self.fmt_head(fmt)?; |
9cc50fc6 SL |
408 | let successors = self.successors(); |
409 | let labels = self.fmt_successor_labels(); | |
410 | assert_eq!(successors.len(), labels.len()); | |
411 | ||
412 | match successors.len() { | |
413 | 0 => Ok(()), | |
414 | ||
415 | 1 => write!(fmt, " -> {:?}", successors[0]), | |
416 | ||
417 | _ => { | |
54a0048b | 418 | write!(fmt, " -> [")?; |
9cc50fc6 SL |
419 | for (i, target) in successors.iter().enumerate() { |
420 | if i > 0 { | |
54a0048b | 421 | write!(fmt, ", ")?; |
9cc50fc6 | 422 | } |
54a0048b | 423 | write!(fmt, "{}: {:?}", labels[i], target)?; |
9cc50fc6 SL |
424 | } |
425 | write!(fmt, "]") | |
426 | } | |
427 | ||
428 | } | |
429 | } | |
430 | } | |
431 | ||
54a0048b | 432 | impl<'tcx> TerminatorKind<'tcx> { |
9cc50fc6 SL |
433 | /// Write the "head" part of the terminator; that is, its name and the data it uses to pick the |
434 | /// successor basic block, if any. The only information not inlcuded is the list of possible | |
435 | /// successors, which may be rendered differently between the text and the graphviz format. | |
436 | pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result { | |
54a0048b | 437 | use self::TerminatorKind::*; |
e9174d1e | 438 | match *self { |
9cc50fc6 SL |
439 | Goto { .. } => write!(fmt, "goto"), |
440 | If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv), | |
441 | Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv), | |
442 | SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv), | |
443 | Return => write!(fmt, "return"), | |
444 | Resume => write!(fmt, "resume"), | |
7453a54e SL |
445 | Drop { ref value, .. } => write!(fmt, "drop({:?})", value), |
446 | Call { ref func, ref args, ref destination, .. } => { | |
447 | if let Some((ref destination, _)) = *destination { | |
54a0048b | 448 | write!(fmt, "{:?} = ", destination)?; |
9cc50fc6 | 449 | } |
54a0048b | 450 | write!(fmt, "{:?}(", func)?; |
9cc50fc6 | 451 | for (index, arg) in args.iter().enumerate() { |
b039eaaf | 452 | if index > 0 { |
54a0048b | 453 | write!(fmt, ", ")?; |
b039eaaf | 454 | } |
54a0048b | 455 | write!(fmt, "{:?}", arg)?; |
e9174d1e | 456 | } |
9cc50fc6 | 457 | write!(fmt, ")") |
e9174d1e SL |
458 | } |
459 | } | |
460 | } | |
9cc50fc6 SL |
461 | |
462 | /// Return the list of labels for the edges to the successor basic blocks. | |
463 | pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> { | |
54a0048b | 464 | use self::TerminatorKind::*; |
9cc50fc6 SL |
465 | match *self { |
466 | Return | Resume => vec![], | |
7453a54e SL |
467 | Goto { .. } => vec!["".into()], |
468 | If { .. } => vec!["true".into(), "false".into()], | |
9cc50fc6 SL |
469 | Switch { ref adt_def, .. } => { |
470 | adt_def.variants | |
471 | .iter() | |
7453a54e | 472 | .map(|variant| variant.name.to_string().into()) |
9cc50fc6 SL |
473 | .collect() |
474 | } | |
475 | SwitchInt { ref values, .. } => { | |
476 | values.iter() | |
477 | .map(|const_val| { | |
478 | let mut buf = String::new(); | |
479 | fmt_const_val(&mut buf, const_val).unwrap(); | |
7453a54e | 480 | buf.into() |
9cc50fc6 | 481 | }) |
7453a54e | 482 | .chain(iter::once(String::from("otherwise").into())) |
9cc50fc6 SL |
483 | .collect() |
484 | } | |
7453a54e SL |
485 | Call { destination: Some(_), cleanup: Some(_), .. } => |
486 | vec!["return".into_cow(), "unwind".into_cow()], | |
487 | Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()], | |
488 | Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()], | |
489 | Call { destination: None, cleanup: None, .. } => vec![], | |
490 | Drop { unwind: None, .. } => vec!["return".into_cow()], | |
491 | Drop { .. } => vec!["return".into_cow(), "unwind".into_cow()], | |
9cc50fc6 SL |
492 | } |
493 | } | |
e9174d1e SL |
494 | } |
495 | ||
496 | ||
497 | /////////////////////////////////////////////////////////////////////////// | |
498 | // Statements | |
499 | ||
7453a54e | 500 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
b039eaaf SL |
501 | pub struct Statement<'tcx> { |
502 | pub span: Span, | |
54a0048b | 503 | pub scope: ScopeId, |
b039eaaf | 504 | pub kind: StatementKind<'tcx>, |
e9174d1e SL |
505 | } |
506 | ||
7453a54e | 507 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] |
b039eaaf SL |
508 | pub enum StatementKind<'tcx> { |
509 | Assign(Lvalue<'tcx>, Rvalue<'tcx>), | |
e9174d1e SL |
510 | } |
511 | ||
b039eaaf | 512 | impl<'tcx> Debug for Statement<'tcx> { |
9cc50fc6 | 513 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
e9174d1e SL |
514 | use self::StatementKind::*; |
515 | match self.kind { | |
7453a54e | 516 | Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv) |
e9174d1e SL |
517 | } |
518 | } | |
519 | } | |
54a0048b | 520 | |
e9174d1e SL |
521 | /////////////////////////////////////////////////////////////////////////// |
522 | // Lvalues | |
523 | ||
524 | /// A path to a value; something that can be evaluated without | |
525 | /// changing or disturbing program state. | |
9cc50fc6 | 526 | #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] |
b039eaaf | 527 | pub enum Lvalue<'tcx> { |
e9174d1e SL |
528 | /// local variable declared by the user |
529 | Var(u32), | |
530 | ||
531 | /// temporary introduced during lowering into MIR | |
532 | Temp(u32), | |
533 | ||
534 | /// formal parameter of the function; note that these are NOT the | |
535 | /// bindings that the user declares, which are vars | |
536 | Arg(u32), | |
537 | ||
538 | /// static or static mut variable | |
b039eaaf | 539 | Static(DefId), |
e9174d1e SL |
540 | |
541 | /// the return pointer of the fn | |
542 | ReturnPointer, | |
543 | ||
544 | /// projection out of an lvalue (access a field, deref a pointer, etc) | |
b039eaaf | 545 | Projection(Box<LvalueProjection<'tcx>>), |
e9174d1e SL |
546 | } |
547 | ||
548 | /// The `Projection` data structure defines things of the form `B.x` | |
549 | /// or `*B` or `B[index]`. Note that it is parameterized because it is | |
550 | /// shared between `Constant` and `Lvalue`. See the aliases | |
551 | /// `LvalueProjection` etc below. | |
54a0048b | 552 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
b039eaaf | 553 | pub struct Projection<'tcx, B, V> { |
e9174d1e | 554 | pub base: B, |
b039eaaf | 555 | pub elem: ProjectionElem<'tcx, V>, |
e9174d1e SL |
556 | } |
557 | ||
54a0048b | 558 | #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
b039eaaf | 559 | pub enum ProjectionElem<'tcx, V> { |
e9174d1e | 560 | Deref, |
7453a54e | 561 | Field(Field, Ty<'tcx>), |
e9174d1e SL |
562 | Index(V), |
563 | ||
7453a54e SL |
564 | /// These indices are generated by slice patterns. Easiest to explain |
565 | /// by example: | |
566 | /// | |
567 | /// ``` | |
568 | /// [X, _, .._, _, _] => { offset: 0, min_length: 4, from_end: false }, | |
569 | /// [_, X, .._, _, _] => { offset: 1, min_length: 4, from_end: false }, | |
570 | /// [_, _, .._, X, _] => { offset: 2, min_length: 4, from_end: true }, | |
571 | /// [_, _, .._, _, X] => { offset: 1, min_length: 4, from_end: true }, | |
572 | /// ``` | |
e9174d1e | 573 | ConstantIndex { |
7453a54e SL |
574 | /// index or -index (in Python terms), depending on from_end |
575 | offset: u32, | |
576 | /// thing being indexed must be at least this long | |
577 | min_length: u32, | |
578 | /// counting backwards from end? | |
579 | from_end: bool, | |
e9174d1e SL |
580 | }, |
581 | ||
7453a54e SL |
582 | /// "Downcast" to a variant of an ADT. Currently, we only introduce |
583 | /// this for ADTs with more than one variant. It may be better to | |
584 | /// just introduce it always, or always for enums. | |
b039eaaf | 585 | Downcast(AdtDef<'tcx>, usize), |
e9174d1e SL |
586 | } |
587 | ||
588 | /// Alias for projections as they appear in lvalues, where the base is an lvalue | |
589 | /// and the index is an operand. | |
9cc50fc6 | 590 | pub type LvalueProjection<'tcx> = Projection<'tcx, Lvalue<'tcx>, Operand<'tcx>>; |
e9174d1e SL |
591 | |
592 | /// Alias for projections as they appear in lvalues, where the base is an lvalue | |
593 | /// and the index is an operand. | |
9cc50fc6 | 594 | pub type LvalueElem<'tcx> = ProjectionElem<'tcx, Operand<'tcx>>; |
e9174d1e | 595 | |
92a42be0 | 596 | /// Index into the list of fields found in a `VariantDef` |
9cc50fc6 | 597 | #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
92a42be0 SL |
598 | pub struct Field(u32); |
599 | ||
600 | impl Field { | |
601 | pub fn new(value: usize) -> Field { | |
602 | assert!(value < (u32::MAX) as usize); | |
603 | Field(value as u32) | |
604 | } | |
605 | ||
606 | pub fn index(self) -> usize { | |
607 | self.0 as usize | |
608 | } | |
e9174d1e SL |
609 | } |
610 | ||
b039eaaf | 611 | impl<'tcx> Lvalue<'tcx> { |
7453a54e SL |
612 | pub fn field(self, f: Field, ty: Ty<'tcx>) -> Lvalue<'tcx> { |
613 | self.elem(ProjectionElem::Field(f, ty)) | |
e9174d1e SL |
614 | } |
615 | ||
b039eaaf | 616 | pub fn deref(self) -> Lvalue<'tcx> { |
e9174d1e SL |
617 | self.elem(ProjectionElem::Deref) |
618 | } | |
619 | ||
b039eaaf | 620 | pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> { |
e9174d1e SL |
621 | self.elem(ProjectionElem::Index(index)) |
622 | } | |
623 | ||
b039eaaf SL |
624 | pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> { |
625 | Lvalue::Projection(Box::new(LvalueProjection { | |
626 | base: self, | |
627 | elem: elem, | |
628 | })) | |
e9174d1e SL |
629 | } |
630 | } | |
631 | ||
b039eaaf | 632 | impl<'tcx> Debug for Lvalue<'tcx> { |
9cc50fc6 | 633 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
e9174d1e SL |
634 | use self::Lvalue::*; |
635 | ||
636 | match *self { | |
637 | Var(id) => | |
9cc50fc6 | 638 | write!(fmt, "var{:?}", id), |
e9174d1e | 639 | Arg(id) => |
9cc50fc6 | 640 | write!(fmt, "arg{:?}", id), |
e9174d1e | 641 | Temp(id) => |
9cc50fc6 SL |
642 | write!(fmt, "tmp{:?}", id), |
643 | Static(def_id) => | |
644 | write!(fmt, "{}", ty::tls::with(|tcx| tcx.item_path_str(def_id))), | |
e9174d1e | 645 | ReturnPointer => |
9cc50fc6 | 646 | write!(fmt, "return"), |
e9174d1e SL |
647 | Projection(ref data) => |
648 | match data.elem { | |
9cc50fc6 SL |
649 | ProjectionElem::Downcast(ref adt_def, index) => |
650 | write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name), | |
e9174d1e | 651 | ProjectionElem::Deref => |
9cc50fc6 | 652 | write!(fmt, "(*{:?})", data.base), |
7453a54e SL |
653 | ProjectionElem::Field(field, ty) => |
654 | write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty), | |
e9174d1e | 655 | ProjectionElem::Index(ref index) => |
9cc50fc6 | 656 | write!(fmt, "{:?}[{:?}]", data.base, index), |
e9174d1e | 657 | ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => |
9cc50fc6 | 658 | write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length), |
e9174d1e | 659 | ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => |
9cc50fc6 | 660 | write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), |
e9174d1e SL |
661 | }, |
662 | } | |
663 | } | |
664 | } | |
665 | ||
54a0048b SL |
666 | /////////////////////////////////////////////////////////////////////////// |
667 | // Scopes | |
668 | ||
669 | impl Index<ScopeId> for Vec<ScopeData> { | |
670 | type Output = ScopeData; | |
671 | ||
672 | #[inline] | |
673 | fn index(&self, index: ScopeId) -> &ScopeData { | |
674 | &self[index.index()] | |
675 | } | |
676 | } | |
677 | ||
678 | impl IndexMut<ScopeId> for Vec<ScopeData> { | |
679 | #[inline] | |
680 | fn index_mut(&mut self, index: ScopeId) -> &mut ScopeData { | |
681 | &mut self[index.index()] | |
682 | } | |
683 | } | |
684 | ||
685 | #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)] | |
686 | pub struct ScopeId(u32); | |
687 | ||
688 | impl ScopeId { | |
689 | pub fn new(index: usize) -> ScopeId { | |
690 | assert!(index < (u32::MAX as usize)); | |
691 | ScopeId(index as u32) | |
692 | } | |
693 | ||
694 | pub fn index(self) -> usize { | |
695 | self.0 as usize | |
696 | } | |
697 | } | |
698 | ||
699 | #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] | |
700 | pub struct ScopeData { | |
701 | pub parent_scope: Option<ScopeId>, | |
702 | } | |
703 | ||
e9174d1e SL |
704 | /////////////////////////////////////////////////////////////////////////// |
705 | // Operands | |
54a0048b | 706 | |
7453a54e SL |
707 | /// These are values that can appear inside an rvalue (or an index |
708 | /// lvalue). They are intentionally limited to prevent rvalues from | |
709 | /// being nested in one another. | |
9cc50fc6 | 710 | #[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)] |
b039eaaf SL |
711 | pub enum Operand<'tcx> { |
712 | Consume(Lvalue<'tcx>), | |
713 | Constant(Constant<'tcx>), | |
e9174d1e SL |
714 | } |
715 | ||
b039eaaf | 716 | impl<'tcx> Debug for Operand<'tcx> { |
9cc50fc6 | 717 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
e9174d1e SL |
718 | use self::Operand::*; |
719 | match *self { | |
720 | Constant(ref a) => write!(fmt, "{:?}", a), | |
721 | Consume(ref lv) => write!(fmt, "{:?}", lv), | |
722 | } | |
723 | } | |
724 | } | |
725 | ||
726 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e | 727 | /// Rvalues |
e9174d1e | 728 | |
9cc50fc6 | 729 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
b039eaaf | 730 | pub enum Rvalue<'tcx> { |
7453a54e | 731 | /// x (either a move or copy, depending on type of x) |
b039eaaf | 732 | Use(Operand<'tcx>), |
e9174d1e | 733 | |
7453a54e SL |
734 | /// [x; 32] |
735 | Repeat(Operand<'tcx>, TypedConstVal<'tcx>), | |
e9174d1e | 736 | |
7453a54e | 737 | /// &x or &mut x |
b039eaaf | 738 | Ref(Region, BorrowKind, Lvalue<'tcx>), |
e9174d1e | 739 | |
7453a54e | 740 | /// length of a [X] or [X;n] value |
b039eaaf | 741 | Len(Lvalue<'tcx>), |
e9174d1e | 742 | |
b039eaaf | 743 | Cast(CastKind, Operand<'tcx>, Ty<'tcx>), |
e9174d1e | 744 | |
b039eaaf | 745 | BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>), |
e9174d1e | 746 | |
b039eaaf | 747 | UnaryOp(UnOp, Operand<'tcx>), |
e9174d1e | 748 | |
7453a54e | 749 | /// Creates an *uninitialized* Box |
b039eaaf | 750 | Box(Ty<'tcx>), |
e9174d1e | 751 | |
7453a54e SL |
752 | /// Create an aggregate value, like a tuple or struct. This is |
753 | /// only needed because we want to distinguish `dest = Foo { x: | |
754 | /// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case | |
755 | /// that `Foo` has a destructor. These rvalues can be optimized | |
756 | /// away after type-checking and before lowering. | |
b039eaaf | 757 | Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>), |
e9174d1e | 758 | |
7453a54e SL |
759 | /// Generates a slice of the form `&input[from_start..L-from_end]` |
760 | /// where `L` is the length of the slice. This is only created by | |
761 | /// slice pattern matching, so e.g. a pattern of the form `[x, y, | |
762 | /// .., z]` might create a slice with `from_start=2` and | |
763 | /// `from_end=1`. | |
e9174d1e | 764 | Slice { |
b039eaaf | 765 | input: Lvalue<'tcx>, |
e9174d1e SL |
766 | from_start: usize, |
767 | from_end: usize, | |
768 | }, | |
769 | ||
54a0048b SL |
770 | InlineAsm { |
771 | asm: InlineAsm, | |
772 | outputs: Vec<Lvalue<'tcx>>, | |
773 | inputs: Vec<Operand<'tcx>> | |
774 | } | |
e9174d1e SL |
775 | } |
776 | ||
7453a54e | 777 | #[derive(Clone, Copy, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
778 | pub enum CastKind { |
779 | Misc, | |
780 | ||
781 | /// Convert unique, zero-sized type for a fn to fn() | |
782 | ReifyFnPointer, | |
783 | ||
784 | /// Convert safe fn() to unsafe fn() | |
785 | UnsafeFnPointer, | |
786 | ||
787 | /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. | |
788 | /// trans must figure out the details once full monomorphization | |
789 | /// is known. For example, this could be used to cast from a | |
790 | /// `&[i32;N]` to a `&[i32]`, or a `Box<T>` to a `Box<Trait>` | |
791 | /// (presuming `T: Trait`). | |
792 | Unsize, | |
793 | } | |
794 | ||
9cc50fc6 | 795 | #[derive(Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
b039eaaf | 796 | pub enum AggregateKind<'tcx> { |
e9174d1e SL |
797 | Vec, |
798 | Tuple, | |
b039eaaf SL |
799 | Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>), |
800 | Closure(DefId, &'tcx ClosureSubsts<'tcx>), | |
e9174d1e SL |
801 | } |
802 | ||
9cc50fc6 | 803 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
804 | pub enum BinOp { |
805 | /// The `+` operator (addition) | |
806 | Add, | |
807 | /// The `-` operator (subtraction) | |
808 | Sub, | |
809 | /// The `*` operator (multiplication) | |
810 | Mul, | |
811 | /// The `/` operator (division) | |
812 | Div, | |
813 | /// The `%` operator (modulus) | |
814 | Rem, | |
815 | /// The `^` operator (bitwise xor) | |
816 | BitXor, | |
817 | /// The `&` operator (bitwise and) | |
818 | BitAnd, | |
819 | /// The `|` operator (bitwise or) | |
820 | BitOr, | |
821 | /// The `<<` operator (shift left) | |
822 | Shl, | |
823 | /// The `>>` operator (shift right) | |
824 | Shr, | |
825 | /// The `==` operator (equality) | |
826 | Eq, | |
827 | /// The `<` operator (less than) | |
828 | Lt, | |
829 | /// The `<=` operator (less than or equal to) | |
830 | Le, | |
831 | /// The `!=` operator (not equal to) | |
832 | Ne, | |
833 | /// The `>=` operator (greater than or equal to) | |
834 | Ge, | |
835 | /// The `>` operator (greater than) | |
836 | Gt, | |
837 | } | |
838 | ||
9cc50fc6 | 839 | #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] |
e9174d1e SL |
840 | pub enum UnOp { |
841 | /// The `!` operator for logical inversion | |
842 | Not, | |
843 | /// The `-` operator for negation | |
b039eaaf | 844 | Neg, |
e9174d1e SL |
845 | } |
846 | ||
b039eaaf | 847 | impl<'tcx> Debug for Rvalue<'tcx> { |
9cc50fc6 | 848 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { |
e9174d1e SL |
849 | use self::Rvalue::*; |
850 | ||
851 | match *self { | |
852 | Use(ref lvalue) => write!(fmt, "{:?}", lvalue), | |
853 | Repeat(ref a, ref b) => write!(fmt, "[{:?}; {:?}]", a, b), | |
9cc50fc6 SL |
854 | Len(ref a) => write!(fmt, "Len({:?})", a), |
855 | Cast(ref kind, ref lv, ref ty) => write!(fmt, "{:?} as {:?} ({:?})", lv, ty, kind), | |
856 | BinaryOp(ref op, ref a, ref b) => write!(fmt, "{:?}({:?}, {:?})", op, a, b), | |
e9174d1e | 857 | UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a), |
9cc50fc6 | 858 | Box(ref t) => write!(fmt, "Box({:?})", t), |
54a0048b SL |
859 | InlineAsm { ref asm, ref outputs, ref inputs } => { |
860 | write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs) | |
861 | } | |
b039eaaf SL |
862 | Slice { ref input, from_start, from_end } => |
863 | write!(fmt, "{:?}[{:?}..-{:?}]", input, from_start, from_end), | |
9cc50fc6 SL |
864 | |
865 | Ref(_, borrow_kind, ref lv) => { | |
866 | let kind_str = match borrow_kind { | |
867 | BorrowKind::Shared => "", | |
868 | BorrowKind::Mut | BorrowKind::Unique => "mut ", | |
869 | }; | |
870 | write!(fmt, "&{}{:?}", kind_str, lv) | |
871 | } | |
872 | ||
873 | Aggregate(ref kind, ref lvs) => { | |
874 | use self::AggregateKind::*; | |
875 | ||
54a0048b SL |
876 | fn fmt_tuple(fmt: &mut Formatter, lvs: &[Operand]) -> fmt::Result { |
877 | let mut tuple_fmt = fmt.debug_tuple(""); | |
9cc50fc6 SL |
878 | for lv in lvs { |
879 | tuple_fmt.field(lv); | |
880 | } | |
881 | tuple_fmt.finish() | |
882 | } | |
883 | ||
884 | match *kind { | |
885 | Vec => write!(fmt, "{:?}", lvs), | |
886 | ||
887 | Tuple => { | |
888 | match lvs.len() { | |
889 | 0 => write!(fmt, "()"), | |
890 | 1 => write!(fmt, "({:?},)", lvs[0]), | |
54a0048b | 891 | _ => fmt_tuple(fmt, lvs), |
9cc50fc6 SL |
892 | } |
893 | } | |
894 | ||
54a0048b | 895 | Adt(adt_def, variant, substs) => { |
9cc50fc6 | 896 | let variant_def = &adt_def.variants[variant]; |
54a0048b SL |
897 | |
898 | ppaux::parameterized(fmt, substs, variant_def.did, | |
899 | ppaux::Ns::Value, &[], | |
900 | |tcx| { | |
901 | tcx.lookup_item_type(variant_def.did).generics | |
902 | })?; | |
9cc50fc6 SL |
903 | |
904 | match variant_def.kind() { | |
54a0048b SL |
905 | ty::VariantKind::Unit => Ok(()), |
906 | ty::VariantKind::Tuple => fmt_tuple(fmt, lvs), | |
9cc50fc6 | 907 | ty::VariantKind::Struct => { |
54a0048b | 908 | let mut struct_fmt = fmt.debug_struct(""); |
9cc50fc6 SL |
909 | for (field, lv) in variant_def.fields.iter().zip(lvs) { |
910 | struct_fmt.field(&field.name.as_str(), lv); | |
911 | } | |
912 | struct_fmt.finish() | |
913 | } | |
914 | } | |
915 | } | |
916 | ||
917 | Closure(def_id, _) => ty::tls::with(|tcx| { | |
918 | if let Some(node_id) = tcx.map.as_local_node_id(def_id) { | |
919 | let name = format!("[closure@{:?}]", tcx.map.span(node_id)); | |
920 | let mut struct_fmt = fmt.debug_struct(&name); | |
921 | ||
922 | tcx.with_freevars(node_id, |freevars| { | |
923 | for (freevar, lv) in freevars.iter().zip(lvs) { | |
924 | let var_name = tcx.local_var_name_str(freevar.def.var_id()); | |
925 | struct_fmt.field(&var_name, lv); | |
926 | } | |
927 | }); | |
928 | ||
929 | struct_fmt.finish() | |
930 | } else { | |
931 | write!(fmt, "[closure]") | |
932 | } | |
933 | }), | |
934 | } | |
935 | } | |
e9174d1e SL |
936 | } |
937 | } | |
938 | } | |
939 | ||
940 | /////////////////////////////////////////////////////////////////////////// | |
7453a54e SL |
941 | /// Constants |
942 | /// | |
943 | /// Two constants are equal if they are the same constant. Note that | |
944 | /// this does not necessarily mean that they are "==" in Rust -- in | |
945 | /// particular one must be wary of `NaN`! | |
e9174d1e | 946 | |
54a0048b | 947 | #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
b039eaaf SL |
948 | pub struct Constant<'tcx> { |
949 | pub span: Span, | |
950 | pub ty: Ty<'tcx>, | |
951 | pub literal: Literal<'tcx>, | |
e9174d1e SL |
952 | } |
953 | ||
7453a54e SL |
954 | #[derive(Clone, RustcEncodable, RustcDecodable)] |
955 | pub struct TypedConstVal<'tcx> { | |
956 | pub ty: Ty<'tcx>, | |
957 | pub span: Span, | |
54a0048b | 958 | pub value: ConstUsize, |
7453a54e SL |
959 | } |
960 | ||
961 | impl<'tcx> Debug for TypedConstVal<'tcx> { | |
962 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { | |
54a0048b | 963 | write!(fmt, "const {}", ConstInt::Usize(self.value)) |
7453a54e SL |
964 | } |
965 | } | |
966 | ||
54a0048b | 967 | #[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] |
b039eaaf SL |
968 | pub enum Literal<'tcx> { |
969 | Item { | |
970 | def_id: DefId, | |
971 | substs: &'tcx Substs<'tcx>, | |
972 | }, | |
973 | Value { | |
974 | value: ConstVal, | |
975 | }, | |
e9174d1e | 976 | } |
9cc50fc6 SL |
977 | |
978 | impl<'tcx> Debug for Constant<'tcx> { | |
979 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { | |
980 | write!(fmt, "{:?}", self.literal) | |
981 | } | |
982 | } | |
983 | ||
984 | impl<'tcx> Debug for Literal<'tcx> { | |
985 | fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { | |
986 | use self::Literal::*; | |
987 | match *self { | |
54a0048b SL |
988 | Item { def_id, substs } => { |
989 | ppaux::parameterized(fmt, substs, def_id, ppaux::Ns::Value, &[], | |
990 | |tcx| tcx.lookup_item_type(def_id).generics) | |
991 | } | |
9cc50fc6 | 992 | Value { ref value } => { |
54a0048b | 993 | write!(fmt, "const ")?; |
9cc50fc6 SL |
994 | fmt_const_val(fmt, value) |
995 | } | |
996 | } | |
997 | } | |
998 | } | |
999 | ||
1000 | /// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. | |
1001 | fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result { | |
54a0048b | 1002 | use middle::const_val::ConstVal::*; |
9cc50fc6 SL |
1003 | match *const_val { |
1004 | Float(f) => write!(fmt, "{:?}", f), | |
54a0048b | 1005 | Integral(n) => write!(fmt, "{}", n), |
9cc50fc6 SL |
1006 | Str(ref s) => write!(fmt, "{:?}", s), |
1007 | ByteStr(ref bytes) => { | |
1008 | let escaped: String = bytes | |
1009 | .iter() | |
1010 | .flat_map(|&ch| ascii::escape_default(ch).map(|c| c as char)) | |
1011 | .collect(); | |
1012 | write!(fmt, "b\"{}\"", escaped) | |
1013 | } | |
1014 | Bool(b) => write!(fmt, "{:?}", b), | |
1015 | Function(def_id) => write!(fmt, "{}", item_path_str(def_id)), | |
1016 | Struct(node_id) | Tuple(node_id) | Array(node_id, _) | Repeat(node_id, _) => | |
1017 | write!(fmt, "{}", node_to_string(node_id)), | |
54a0048b SL |
1018 | Char(c) => write!(fmt, "{:?}", c), |
1019 | Dummy => bug!(), | |
9cc50fc6 SL |
1020 | } |
1021 | } | |
1022 | ||
1023 | fn node_to_string(node_id: ast::NodeId) -> String { | |
1024 | ty::tls::with(|tcx| tcx.map.node_to_user_string(node_id)) | |
1025 | } | |
1026 | ||
1027 | fn item_path_str(def_id: DefId) -> String { | |
1028 | ty::tls::with(|tcx| tcx.item_path_str(def_id)) | |
1029 | } |