diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 8958a31b51cb..7a52dea787a2 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -151,6 +151,16 @@ impl BodyCache<'tcx> { } } +#[macro_export] +macro_rules! read_only { + ($body_cache:expr) => { + { + $body_cache.ensure_predecessors(); + $body_cache.unwrap_read_only() + } + }; +} + impl BodyCache<'tcx> { pub fn ensure_predecessors(&mut self) { self.cache.ensure_predecessors(&self.body); @@ -160,12 +170,8 @@ impl BodyCache<'tcx> { self.cache.predecessors(&self.body) } - pub fn read_only(&self) -> ReadOnlyBodyCache<'_, '_> { - assert!(self.cache.predecessors.is_some(), ""); - ReadOnlyBodyCache { - cache: &self.cache, - body: &self.body, - } + pub fn unwrap_read_only(&self) -> ReadOnlyBodyCache<'_, 'tcx> { + ReadOnlyBodyCache::new(&self.cache, &self.body) } pub fn body(&self) -> &Body<'tcx> { @@ -176,6 +182,8 @@ impl BodyCache<'tcx> { &mut self.body } + pub fn cache(&self) -> &Cache { &self.cache } + pub fn basic_blocks_mut(&mut self) -> &mut IndexVec> { self.cache.basic_blocks_mut(&mut self.body) } @@ -223,6 +231,24 @@ pub struct ReadOnlyBodyCache<'a, 'tcx> { } impl ReadOnlyBodyCache<'a, 'tcx> { + fn new(cache: &'a Cache, body: &'a Body<'tcx>) -> Self { + assert!( + cache.predecessors.is_some(), + "Cannot construct ReadOnlyBodyCache without computed predecessors"); + Self { + cache, + body, + } + } + + pub fn from_external_cache(cache: &'a mut Cache, body: &'a Body<'tcx>) -> Self { + cache.ensure_predecessors(body); + Self { + cache, + body, + } + } + #[inline] pub fn predecessors(&self) -> &IndexVec> { self.cache.predecessors.as_ref().unwrap() diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index b6d1c78cc4f5..fdc3adabf0c5 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -38,7 +38,9 @@ use syntax::symbol::Symbol; use syntax_pos::{Span, DUMMY_SP}; pub use crate::mir::interpret::AssertMessage; -pub use crate::mir::cache::{BodyCache, ReadOnlyBodyCache}; +// TODO(nashenas88) Cache only exported for use in librustc_mir/transform/check_unsafety.rs +pub use crate::mir::cache::{BodyCache, Cache, ReadOnlyBodyCache}; +pub use crate::read_only; pub mod cache; pub mod interpret; diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index cdfdcee5823e..2bf7caceb68e 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -147,7 +147,13 @@ rustc_queries! { crate::mir::Promoted, crate::mir::BodyCache<'tcx> >> = tcx.queries.on_disk_cache.try_load_query_result(tcx, id); - promoted.map(|p| &*tcx.arena.alloc(p)) + promoted.map(|p| { + let cache = tcx.arena.alloc(p); + for body_cache in cache.iter_mut() { + body_cache.ensure_predecessors(); + } + &*cache + }) } } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index f8feff0def97..cf9fd401e7b1 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -2988,7 +2988,7 @@ impl<'tcx> TyCtxt<'tcx> { pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> ReadOnlyBodyCache<'tcx, 'tcx> { match instance { ty::InstanceDef::Item(did) => { - self.optimized_mir(did).read_only() + self.optimized_mir(did).unwrap_read_only() } ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | @@ -2998,7 +2998,7 @@ impl<'tcx> TyCtxt<'tcx> { ty::InstanceDef::ClosureOnceShim { .. } | ty::InstanceDef::DropGlue(..) | ty::InstanceDef::CloneShim(..) => { - self.mir_shims(instance).read_only() + self.mir_shims(instance).unwrap_read_only() } } } diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 30dad03648c9..c163ff85563b 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -1080,12 +1080,14 @@ impl<'a, 'tcx> CrateMetadata { } fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> BodyCache<'tcx> { - self.root.per_def.mir.get(self, id) + let mut cache = self.root.per_def.mir.get(self, id) .filter(|_| !self.is_proc_macro(id)) .unwrap_or_else(|| { bug!("get_optimized_mir: missing MIR for `{:?}`", self.local_def_id(id)) }) - .decode((self, tcx)) + .decode((self, tcx)); + cache.ensure_predecessors(); + cache } fn get_promoted_mir( @@ -1093,12 +1095,16 @@ impl<'a, 'tcx> CrateMetadata { tcx: TyCtxt<'tcx>, id: DefIndex, ) -> IndexVec> { - self.root.per_def.promoted_mir.get(self, id) + let mut cache = self.root.per_def.promoted_mir.get(self, id) .filter(|_| !self.is_proc_macro(id)) .unwrap_or_else(|| { bug!("get_promoted_mir: missing MIR for `{:?}`", self.local_def_id(id)) }) - .decode((self, tcx)) + .decode((self, tcx)); + for body_cache in cache.iter_mut() { + body_cache.ensure_predecessors(); + } + cache } fn mir_const_qualif(&self, id: DefIndex) -> mir::ConstQualifs { diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 0170cc8b42ab..6205638c24a0 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -10,7 +10,7 @@ use rustc::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT}; use rustc::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc::mir::{ ClearCrossCrate, Local, Location, Body, BodyCache, Mutability, Operand, Place, PlaceBase, - PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind + PlaceElem, PlaceRef, ReadOnlyBodyCache, Static, StaticKind, read_only }; use rustc::mir::{Field, ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; use rustc::mir::{Terminator, TerminatorKind}; @@ -167,8 +167,8 @@ fn do_mir_borrowck<'a, 'tcx>( let mut body_cache = BodyCache::new(body); let free_regions = nll::replace_regions_in_mir(infcx, def_id, param_env, &mut body_cache, &mut promoted); - let body_cache = body_cache.read_only(); // no further changes - let promoted: IndexVec<_, _> = promoted.iter().map(|body_cache| body_cache.read_only()).collect(); + let body_cache = read_only!(body_cache); // no further changes + let promoted: IndexVec<_, _> = promoted.iter_mut().map(|body_cache| read_only!(body_cache)).collect(); let location_table = &LocationTable::new(&body_cache); @@ -492,7 +492,7 @@ impl<'cx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx type FlowState = Flows<'cx, 'tcx>; fn body(&self) -> &'cx Body<'tcx> { - &self.body_cache + self.body_cache.body() } fn visit_block_entry(&mut self, bb: BasicBlock, flow_state: &Self::FlowState) { diff --git a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs index 9a0392ab1d83..1eaa82ec08e2 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/liveness/trace.rs @@ -302,7 +302,8 @@ impl LivenessResults<'me, 'typeck, 'flow, 'tcx> { } } - for &pred_block in self.cx.body_cache.predecessors_for(block).iter() { + let body_cache = self.cx.body_cache; + for &pred_block in body_cache.predecessors_for(block).iter() { debug!("compute_drop_live_points_for_block: pred_block = {:?}", pred_block,); // Check whether the variable is (at least partially) diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 92efd383c3c8..e1750af6693c 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -540,7 +540,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // checker on the promoted MIR, then transfer the constraints back to // the main MIR, changing the locations to the provided location. - let parent_body = mem::replace(&mut self.body, &promoted_body_cache); + let parent_body = mem::replace(&mut self.body, promoted_body_cache.body()); // Use new sets of constraints and closure bounds so that we can // modify their locations. diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/src/librustc_mir/borrow_check/prefixes.rs index aa02c0641e35..ccd6d285a7bc 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/src/librustc_mir/borrow_check/prefixes.rs @@ -56,7 +56,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Prefixes { next: Some(place_ref), kind, - body: &self.body_cache, + body: self.body_cache.body(), tcx: self.infcx.tcx, } } diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 043ba09f52a9..044e3c4a9b32 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -303,11 +303,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); if let Some(promoted) = promoted { - return Ok(self.tcx.promoted_mir(did)[promoted].read_only()); + return Ok(self.tcx.promoted_mir(did)[promoted].unwrap_read_only()); } match instance { ty::InstanceDef::Item(def_id) => if self.tcx.is_mir_available(did) { - Ok(self.tcx.optimized_mir(did).read_only()) + Ok(self.tcx.optimized_mir(did).unwrap_read_only()) } else { throw_unsup!(NoMirFor(self.tcx.def_path_str(def_id))) }, diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 8f97a4e7f5c8..0f91b8b28bcf 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -125,6 +125,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> &'tcx debug!("make_shim({:?}) = {:?}", instance, result.body()); + result.ensure_predecessors(); tcx.arena.alloc(result) } @@ -928,5 +929,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> &BodyCache<'_> { |_, _| Ok(()), ); - tcx.arena.alloc(BodyCache::new(body)) + let mut body_cache = BodyCache::new(body); + body_cache.ensure_predecessors(); + tcx.arena.alloc(body_cache) } diff --git a/src/librustc_mir/transform/check_unsafety.rs b/src/librustc_mir/transform/check_unsafety.rs index 78628474bce9..d2d4eef1164e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/src/librustc_mir/transform/check_unsafety.rs @@ -516,7 +516,7 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult // N.B., this borrow is valid because all the consumers of // `mir_built` force this. - let body = &tcx.mir_built(def_id).borrow(); + let body_cache = &tcx.mir_built(def_id).borrow(); let param_env = tcx.param_env(def_id); @@ -527,8 +527,10 @@ fn unsafety_check_result(tcx: TyCtxt<'_>, def_id: DefId) -> UnsafetyCheckResult hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => (true, false), }; - let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body, tcx, param_env); - checker.visit_body(body.read_only()); + let mut checker = UnsafetyChecker::new(const_context, min_const_fn, body_cache, tcx, param_env); + let mut cache = body_cache.cache().clone(); + let read_only_cache = ReadOnlyBodyCache::from_external_cache(&mut cache, body_cache.body()); + checker.visit_body(read_only_cache); check_unused_unsafe(tcx, def_id, &checker.used_unsafe, &mut checker.inherited_blocks); UnsafetyCheckResult { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index f79f375a7e84..fdfbe59f078b 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -10,7 +10,7 @@ use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, BodyCache, Operand, Local, UnOp, Rvalue. StatementKind, Statement, LocalKind, TerminatorKind, Terminator, ClearCrossCrate, SourceInfo, BinOp, SourceScope, SourceScopeData, LocalDecl, BasicBlock, ReadOnlyBodyCache, - RETURN_PLACE + read_only, RETURN_PLACE }; use rustc::mir::visit::{ Visitor, PlaceContext, MutatingUseContext, MutVisitor, NonMutatingUseContext, @@ -93,7 +93,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { // That would require an uniform one-def no-mutation analysis // and RPO (or recursing when needing the value of a local). let mut optimization_finder = ConstPropagator::new( - body_cache.read_only(), + read_only!(body_cache), dummy_body, tcx, source @@ -285,7 +285,7 @@ impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> { impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new( - body_cache: ReadOnlyBodyCache<'mir, 'tcx>, + body_cache: ReadOnlyBodyCache<'_, 'tcx>, dummy_body: &'mir Body<'tcx>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 637f4792029a..decd3f65c812 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -21,7 +21,7 @@ use rustc::mir::{ Constant, Local, LocalKind, Location, Place, Body, BodyCache, Operand, Rvalue, - StatementKind + StatementKind, read_only }; use rustc::mir::visit::MutVisitor; use rustc::ty::TyCtxt; @@ -40,10 +40,10 @@ impl<'tcx> MirPass<'tcx> for CopyPropagation { let mut def_use_analysis = DefUseAnalysis::new(body_cache); loop { - def_use_analysis.analyze(body_cache.read_only()); + def_use_analysis.analyze(read_only!(body_cache)); if eliminate_self_assignments(body_cache, &def_use_analysis) { - def_use_analysis.analyze(body_cache.read_only()); + def_use_analysis.analyze(read_only!(body_cache)); } let mut changed = false; diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 503d24e56ae7..343cd8e47b28 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -759,7 +759,7 @@ fn compute_layout<'tcx>( // Use a liveness analysis to compute locals which are live across a suspension point let LivenessInfo { live_locals, live_locals_at_suspension_points, storage_conflicts, storage_liveness - } = locals_live_across_suspend_points(tcx, body_cache.read_only(), source, movable); + } = locals_live_across_suspend_points(tcx, read_only!(body_cache), source, movable); // Erase regions from the types passed in from typeck so we can compare them with // MIR types diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs index c1c3d39bdc08..f4f7584bfabd 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/src/librustc_mir/transform/inline.rs @@ -514,7 +514,7 @@ impl Inliner<'tcx> { &self, args: Vec>, callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, + caller_body_cache: &mut BodyCache<'tcx>, ) -> Vec { let tcx = self.tcx; @@ -543,12 +543,12 @@ impl Inliner<'tcx> { // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. if tcx.is_closure(callsite.callee) { let mut args = args.into_iter(); - let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); - let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); + let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body_cache); + let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body_cache); assert!(args.next().is_none()); let tuple = Place::from(tuple); - let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind { + let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body_cache.body(), tcx).ty.kind { s } else { bug!("Closure arguments are not passed as a tuple"); @@ -568,13 +568,13 @@ impl Inliner<'tcx> { )); // Spill to a local to make e.g., `tmp0`. - self.create_temp_if_necessary(tuple_field, callsite, caller_body) + self.create_temp_if_necessary(tuple_field, callsite, caller_body_cache) }); closure_ref_arg.chain(tuple_tmp_args).collect() } else { args.into_iter() - .map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) + .map(|a| self.create_temp_if_necessary(a, callsite, caller_body_cache)) .collect() } } @@ -585,14 +585,14 @@ impl Inliner<'tcx> { &self, arg: Operand<'tcx>, callsite: &CallSite<'tcx>, - caller_body: &mut Body<'tcx>, + caller_body_cache: &mut BodyCache<'tcx>, ) -> Local { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. if let Operand::Move(place) = &arg { if let Some(local) = place.as_local() { - if caller_body.local_kind(local) == LocalKind::Temp { + if caller_body_cache.local_kind(local) == LocalKind::Temp { // Reuse the operand if it's a temporary already return local; } @@ -603,16 +603,16 @@ impl Inliner<'tcx> { // Otherwise, create a temporary for the arg let arg = Rvalue::Use(arg); - let ty = arg.ty(caller_body, self.tcx); + let ty = arg.ty(caller_body_cache.body(), self.tcx); let arg_tmp = LocalDecl::new_temp(ty, callsite.location.span); - let arg_tmp = caller_body.local_decls.push(arg_tmp); + let arg_tmp = caller_body_cache.local_decls.push(arg_tmp); let stmt = Statement { source_info: callsite.location, kind: StatementKind::Assign(box(Place::from(arg_tmp), arg)), }; - caller_body[callsite.bb].statements.push(stmt); + caller_body_cache[callsite.bb].statements.push(stmt); arg_tmp } } diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs index e466b0cb77b7..d8c5c2e0bcab 100644 --- a/src/librustc_mir/transform/instcombine.rs +++ b/src/librustc_mir/transform/instcombine.rs @@ -2,7 +2,7 @@ use rustc::mir::{ Constant, Location, Place, PlaceBase, PlaceRef, Body, BodyCache, Operand, ProjectionElem, - Rvalue, Local + Rvalue, Local, read_only }; use rustc::mir::visit::{MutVisitor, Visitor}; use rustc::ty::{self, TyCtxt}; @@ -24,8 +24,9 @@ impl<'tcx> MirPass<'tcx> for InstCombine { // read-only so that we can do global analyses on the MIR in the process (e.g. // `Place::ty()`). let optimizations = { + let read_only_cache = read_only!(body_cache); let mut optimization_finder = OptimizationFinder::new(body_cache, tcx); - optimization_finder.visit_body(body_cache.read_only()); + optimization_finder.visit_body(read_only_cache); optimization_finder.optimizations }; diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 97c4efc08a37..6c0badff89eb 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/src/librustc_mir/transform/mod.rs @@ -334,6 +334,7 @@ fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &BodyCache<'_> { let (body, _) = tcx.mir_validated(def_id); let mut body_cache = body.steal(); run_optimization_passes(tcx, &mut body_cache, def_id, None); + body_cache.ensure_predecessors(); tcx.arena.alloc(body_cache) } @@ -348,6 +349,7 @@ fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec MirPass<'tcx> for SimplifyLocals { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body_cache: &mut BodyCache<'tcx>) { trace!("running SimplifyLocals on {:?}", source); let locals = { + let read_only_cache = read_only!(body_cache); let mut marker = DeclMarker { locals: BitSet::new_empty(body_cache.local_decls.len()), body: body_cache, }; - marker.visit_body(body_cache.read_only()); + marker.visit_body(read_only_cache); // Return pointer and arguments are always live marker.locals.insert(RETURN_PLACE); for arg in body_cache.args_iter() { diff --git a/src/librustc_mir/transform/uniform_array_move_out.rs b/src/librustc_mir/transform/uniform_array_move_out.rs index d3fbfaf384a9..784ccf5a6b68 100644 --- a/src/librustc_mir/transform/uniform_array_move_out.rs +++ b/src/librustc_mir/transform/uniform_array_move_out.rs @@ -41,8 +41,9 @@ impl<'tcx> MirPass<'tcx> for UniformArrayMoveOut { let mut patch = MirPatch::new(body_cache); let param_env = tcx.param_env(src.def_id()); { + let read_only_cache = read_only!(body_cache); let mut visitor = UniformArrayMoveOutVisitor{ body: body_cache, patch: &mut patch, tcx, param_env}; - visitor.visit_body(body_cache.read_only()); + visitor.visit_body(read_only_cache); } patch.apply(body_cache); } @@ -188,11 +189,12 @@ impl<'tcx> MirPass<'tcx> for RestoreSubsliceArrayMoveOut<'tcx> { let mut patch = MirPatch::new(body_cache); let param_env = tcx.param_env(src.def_id()); { + let read_only_cache = read_only!(body_cache); let mut visitor = RestoreDataCollector { locals_use: IndexVec::from_elem(LocalUse::new(), &body_cache.local_decls), candidates: vec![], }; - visitor.visit_body(body_cache.read_only()); + visitor.visit_body(read_only_cache); for candidate in &visitor.candidates { let statement = &body_cache[candidate.block].statements[candidate.statement_index];