]> git.lizzy.rs Git - rust.git/blob - src/interpreter/stepper.rs
print errors in one central location
[rust.git] / src / interpreter / stepper.rs
1 use super::{
2     CachedMir,
3     ConstantId,
4     GlobalEvalContext,
5     ConstantKind,
6 };
7 use error::EvalResult;
8 use rustc::mir::repr as mir;
9 use rustc::ty::{subst, self};
10 use rustc::hir::def_id::DefId;
11 use rustc::mir::visit::{Visitor, LvalueContext};
12 use syntax::codemap::Span;
13 use std::rc::Rc;
14 use memory::Pointer;
15
16 pub struct Stepper<'fncx, 'a: 'fncx, 'tcx: 'a>{
17     gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>,
18
19     // a cache of the constants to be computed before the next statement/terminator
20     // this is an optimization, so we don't have to allocate a new vector for every statement
21     constants: Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'a, 'tcx>)>,
22 }
23
24 impl<'fncx, 'a, 'tcx> Stepper<'fncx, 'a, 'tcx> {
25     pub(super) fn new(gecx: &'fncx mut GlobalEvalContext<'a, 'tcx>) -> Self {
26         Stepper {
27             gecx: gecx,
28             constants: Vec::new(),
29         }
30     }
31
32     fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<()> {
33         trace!("{:?}", stmt);
34         let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
35         self.gecx.eval_assignment(lvalue, rvalue)?;
36         self.gecx.frame_mut().stmt += 1;
37         Ok(())
38     }
39
40     fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<()> {
41         // after a terminator we go to a new block
42         self.gecx.frame_mut().stmt = 0;
43         trace!("{:?}", terminator.kind);
44         self.gecx.eval_terminator(terminator)?;
45         if !self.gecx.stack.is_empty() {
46             trace!("// {:?}", self.gecx.frame().next_block);
47         }
48         Ok(())
49     }
50
51     // returns true as long as there are more things to do
52     pub fn step(&mut self) -> EvalResult<bool> {
53         if self.gecx.stack.is_empty() {
54             return Ok(false);
55         }
56
57         let block = self.gecx.frame().next_block;
58         let stmt = self.gecx.frame().stmt;
59         let mir = self.gecx.mir();
60         let basic_block = mir.basic_block_data(block);
61
62         if let Some(ref stmt) = basic_block.statements.get(stmt) {
63             assert!(self.constants.is_empty());
64             ConstantExtractor {
65                 span: stmt.span,
66                 substs: self.gecx.substs(),
67                 def_id: self.gecx.frame().def_id,
68                 gecx: self.gecx,
69                 constants: &mut self.constants,
70                 mir: &mir,
71             }.visit_statement(block, stmt);
72             if self.constants.is_empty() {
73                 self.statement(stmt)?;
74             } else {
75                 self.extract_constants()?;
76             }
77             return Ok(true);
78         }
79
80         let terminator = basic_block.terminator();
81         assert!(self.constants.is_empty());
82         ConstantExtractor {
83             span: terminator.span,
84             substs: self.gecx.substs(),
85             def_id: self.gecx.frame().def_id,
86             gecx: self.gecx,
87             constants: &mut self.constants,
88             mir: &mir,
89         }.visit_terminator(block, terminator);
90         if self.constants.is_empty() {
91             self.terminator(terminator)?;
92         } else {
93             self.extract_constants()?;
94         }
95         Ok(true)
96     }
97
98     fn extract_constants(&mut self) -> EvalResult<()> {
99         assert!(!self.constants.is_empty());
100         for (cid, span, return_ptr, mir) in self.constants.drain(..) {
101             trace!("queuing a constant");
102             self.gecx.push_stack_frame(cid.def_id, span, mir, cid.substs, Some(return_ptr));
103         }
104         // self.step() can't be "done", so it can't return false
105         assert!(self.step()?);
106         Ok(())
107     }
108 }
109
110 struct ConstantExtractor<'a, 'b: 'mir, 'mir: 'a, 'tcx: 'b> {
111     span: Span,
112     // FIXME: directly push the new stackframes instead of doing this intermediate caching
113     constants: &'a mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
114     gecx: &'a mut GlobalEvalContext<'b, 'tcx>,
115     mir: &'a mir::Mir<'tcx>,
116     def_id: DefId,
117     substs: &'tcx subst::Substs<'tcx>,
118 }
119
120 impl<'a, 'b, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'mir, 'tcx> {
121     fn global_item(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) {
122         let cid = ConstantId {
123             def_id: def_id,
124             substs: substs,
125             kind: ConstantKind::Global,
126         };
127         if self.gecx.statics.contains_key(&cid) {
128             return;
129         }
130         let mir = self.gecx.load_mir(def_id);
131         let ptr = self.gecx.alloc_ret_ptr(mir.return_ty, substs).expect("there's no such thing as an unreachable static");
132         self.gecx.statics.insert(cid.clone(), ptr);
133         self.constants.push((cid, span, ptr, mir));
134     }
135 }
136
137 impl<'a, 'b, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'mir, 'tcx> {
138     fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) {
139         self.super_constant(constant);
140         match constant.literal {
141             // already computed by rustc
142             mir::Literal::Value { .. } => {}
143             mir::Literal::Item { def_id, substs } => {
144                 if let ty::TyFnDef(..) = constant.ty.sty {
145                     // No need to do anything here, even if function pointers are implemented,
146                     // because the type is the actual function, not the signature of the function.
147                     // Thus we can simply create a zero sized allocation in `evaluate_operand`
148                 } else {
149                     self.global_item(def_id, substs, constant.span);
150                 }
151             },
152             mir::Literal::Promoted { index } => {
153                 let cid = ConstantId {
154                     def_id: self.def_id,
155                     substs: self.substs,
156                     kind: ConstantKind::Promoted(index),
157                 };
158                 if self.gecx.statics.contains_key(&cid) {
159                     return;
160                 }
161                 let mir = self.mir.promoted[index].clone();
162                 let return_ty = mir.return_ty;
163                 let return_ptr = self.gecx.alloc_ret_ptr(return_ty, cid.substs).expect("there's no such thing as an unreachable static");
164                 let mir = CachedMir::Owned(Rc::new(mir));
165                 self.gecx.statics.insert(cid.clone(), return_ptr);
166                 self.constants.push((cid, constant.span, return_ptr, mir));
167             }
168         }
169     }
170
171     fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) {
172         self.super_lvalue(lvalue, context);
173         if let mir::Lvalue::Static(def_id) = *lvalue {
174             let substs = self.gecx.tcx.mk_substs(subst::Substs::empty());
175             let span = self.span;
176             self.global_item(def_id, substs, span);
177         }
178     }
179 }