8 use rustc::mir::repr as mir;
9 use rustc::ty::subst::{self, Subst};
10 use rustc::hir::def_id::DefId;
11 use rustc::mir::visit::{Visitor, LvalueContext};
12 use syntax::codemap::Span;
23 pub struct Stepper<'fncx, 'a: 'fncx, 'b: 'a + 'mir, 'mir: 'fncx, 'tcx: 'b>{
24 fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
25 mir: CachedMir<'mir, 'tcx>,
26 process: fn (&mut Stepper<'fncx, 'a, 'b, 'mir, 'tcx>) -> EvalResult<()>,
27 // a stack of constants
28 constants: Vec<Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>>,
31 impl<'fncx, 'a, 'b: 'a + 'mir, 'mir, 'tcx: 'b> Stepper<'fncx, 'a, 'b, 'mir, 'tcx> {
32 pub(super) fn new(fncx: &'fncx mut FnEvalContext<'a, 'b, 'mir, 'tcx>) -> Self {
37 constants: vec![Vec::new()],
41 fn dummy(&mut self) -> EvalResult<()> { Ok(()) }
43 fn statement(&mut self) -> EvalResult<()> {
44 let block_data = self.mir.basic_block_data(self.fncx.frame().next_block);
45 let stmt = &block_data.statements[self.fncx.frame().stmt];
46 let mir::StatementKind::Assign(ref lvalue, ref rvalue) = stmt.kind;
47 let result = self.fncx.eval_assignment(lvalue, rvalue);
48 self.fncx.maybe_report(stmt.span, result)?;
49 self.fncx.frame_mut().stmt += 1;
53 fn terminator(&mut self) -> EvalResult<()> {
54 // after a terminator we go to a new block
55 self.fncx.frame_mut().stmt = 0;
57 let block_data = self.mir.basic_block_data(self.fncx.frame().next_block);
58 let terminator = block_data.terminator();
59 let result = self.fncx.eval_terminator(terminator);
60 self.fncx.maybe_report(terminator.span, result)?
63 TerminatorTarget::Block => {},
64 TerminatorTarget::Return => {
65 self.fncx.pop_stack_frame();
66 assert!(self.constants.last().unwrap().is_empty());
68 if !self.fncx.stack.is_empty() {
69 self.mir = self.fncx.mir();
72 TerminatorTarget::Call => {
73 self.mir = self.fncx.mir();
74 self.constants.push(Vec::new());
80 fn constant(&mut self) -> EvalResult<()> {
81 match self.constants.last_mut().unwrap().pop() {
82 Some((ConstantId::Promoted { index }, span, return_ptr, mir)) => {
83 trace!("adding promoted constant {}, {:?}", index, span);
84 let substs = self.fncx.substs();
85 // FIXME: somehow encode that this is a promoted constant's frame
86 let def_id = self.fncx.frame().def_id;
87 self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr));
88 self.constants.push(Vec::new());
89 self.mir = self.fncx.mir();
91 Some((ConstantId::Static { def_id, substs }, span, return_ptr, mir)) => {
92 trace!("adding static {:?}, {:?}", def_id, span);
93 self.fncx.gecx.statics.insert(def_id, return_ptr);
94 self.fncx.push_stack_frame(def_id, span, mir, substs, Some(return_ptr));
95 self.constants.push(Vec::new());
96 self.mir = self.fncx.mir();
98 None => unreachable!(),
103 pub fn step(&mut self) -> EvalResult<Event> {
104 (self.process)(self)?;
106 if self.fncx.stack.is_empty() {
108 self.process = Self::dummy;
109 return Ok(Event::Done);
112 if !self.constants.last().unwrap().is_empty() {
113 self.process = Self::constant;
114 return Ok(Event::Constant);
117 let block = self.fncx.frame().next_block;
118 let stmt = self.fncx.frame().stmt;
119 let basic_block = self.mir.basic_block_data(block);
121 if let Some(ref stmt) = basic_block.statements.get(stmt) {
122 assert!(self.constants.last().unwrap().is_empty());
124 constants: &mut self.constants.last_mut().unwrap(),
128 }.visit_statement(block, stmt);
129 if self.constants.last().unwrap().is_empty() {
130 self.process = Self::statement;
131 return Ok(Event::Assignment);
133 self.process = Self::constant;
134 return Ok(Event::Constant);
138 let terminator = basic_block.terminator();
140 constants: &mut self.constants.last_mut().unwrap(),
141 span: terminator.span,
144 }.visit_terminator(block, terminator);
145 if self.constants.last().unwrap().is_empty() {
146 self.process = Self::terminator;
147 Ok(Event::Terminator)
149 self.process = Self::constant;
150 return Ok(Event::Constant);
154 /// returns the statement that will be processed next
155 pub fn stmt(&self) -> &mir::Statement {
156 &self.fncx.basic_block().statements[self.fncx.frame().stmt]
159 /// returns the terminator of the current block
160 pub fn term(&self) -> &mir::Terminator {
161 self.fncx.basic_block().terminator()
164 pub fn block(&self) -> mir::BasicBlock {
165 self.fncx.frame().next_block
169 struct ConstantExtractor<'a: 'c, 'b: 'a + 'mir + 'c, 'c, 'mir: 'c, 'tcx: 'a + 'b + 'c> {
170 constants: &'c mut Vec<(ConstantId<'tcx>, Span, Pointer, CachedMir<'mir, 'tcx>)>,
172 mir: &'c mir::Mir<'tcx>,
173 fncx: &'c mut FnEvalContext<'a, 'b, 'mir, 'tcx>,
176 impl<'a, 'b, 'c, 'mir, 'tcx> ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> {
177 fn constant(&mut self, def_id: DefId, substs: &'tcx subst::Substs<'tcx>, span: Span) {
178 if self.fncx.gecx.statics.contains_key(&def_id) {
181 let cid = ConstantId::Static {
185 let mir = self.fncx.load_mir(def_id);
186 let ptr = self.fncx.alloc_ret_ptr(mir.return_ty).expect("there's no such thing as an unreachable static");
187 self.constants.push((cid, span, ptr, mir));
191 impl<'a, 'b, 'c, 'mir, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'c, 'mir, 'tcx> {
192 fn visit_constant(&mut self, constant: &mir::Constant<'tcx>) {
193 self.super_constant(constant);
194 match constant.literal {
195 // already computed by rustc
196 mir::Literal::Value { .. } => {}
197 mir::Literal::Item { def_id, substs } => {
198 let item_ty = self.fncx.tcx.lookup_item_type(def_id).subst(self.fncx.tcx, substs);
199 if item_ty.ty.is_fn() {
202 self.constant(def_id, substs, constant.span);
205 mir::Literal::Promoted { index } => {
206 if self.fncx.frame().promoted.contains_key(&index) {
209 let mir = self.mir.promoted[index].clone();
210 let return_ty = mir.return_ty;
211 let return_ptr = self.fncx.alloc_ret_ptr(return_ty).expect("there's no such thing as an unreachable static");
212 self.fncx.frame_mut().promoted.insert(index, return_ptr);
213 let mir = CachedMir::Owned(Rc::new(mir));
214 self.constants.push((ConstantId::Promoted { index: index }, constant.span, return_ptr, mir));
219 fn visit_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>, context: LvalueContext) {
220 self.super_lvalue(lvalue, context);
221 if let mir::Lvalue::Static(def_id) = *lvalue {
222 let substs = self.fncx.tcx.mk_substs(subst::Substs::empty());
223 let span = self.span;
224 self.constant(def_id, substs, span);