rustc_borrowck/type_check/liveness/
mod.rsuse itertools::{Either, Itertools};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::mir::visit::{TyContext, Visitor};
use rustc_middle::mir::{Body, Local, Location, SourceInfo};
use rustc_middle::span_bug;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{GenericArgsRef, Region, RegionVid, Ty, TyCtxt};
use rustc_mir_dataflow::ResultsCursor;
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::points::DenseLocationMap;
use tracing::debug;
use super::TypeChecker;
use crate::constraints::OutlivesConstraintSet;
use crate::region_infer::values::LivenessValues;
use crate::universal_regions::UniversalRegions;
mod local_use_map;
mod polonius;
mod trace;
pub(super) fn generate<'a, 'tcx>(
typeck: &mut TypeChecker<'_, 'tcx>,
body: &Body<'tcx>,
elements: &DenseLocationMap,
flow_inits: &mut ResultsCursor<'a, 'tcx, MaybeInitializedPlaces<'a, 'tcx>>,
move_data: &MoveData<'tcx>,
) {
debug!("liveness::generate");
let free_regions = regions_that_outlive_free_regions(
typeck.infcx.num_region_vars(),
typeck.borrowck_context.universal_regions,
&typeck.borrowck_context.constraints.outlives_constraints,
);
let (relevant_live_locals, boring_locals) =
compute_relevant_live_locals(typeck.tcx(), &free_regions, body);
polonius::populate_access_facts(typeck, body, move_data);
trace::trace(
typeck,
body,
elements,
flow_inits,
move_data,
relevant_live_locals,
boring_locals,
);
record_regular_live_regions(
typeck.tcx(),
&mut typeck.borrowck_context.constraints.liveness_constraints,
body,
);
}
fn compute_relevant_live_locals<'tcx>(
tcx: TyCtxt<'tcx>,
free_regions: &FxHashSet<RegionVid>,
body: &Body<'tcx>,
) -> (Vec<Local>, Vec<Local>) {
let (boring_locals, relevant_live_locals): (Vec<_>, Vec<_>) =
body.local_decls.iter_enumerated().partition_map(|(local, local_decl)| {
if tcx.all_free_regions_meet(&local_decl.ty, |r| free_regions.contains(&r.as_var())) {
Either::Left(local)
} else {
Either::Right(local)
}
});
debug!("{} total variables", body.local_decls.len());
debug!("{} variables need liveness", relevant_live_locals.len());
debug!("{} regions outlive free regions", free_regions.len());
(relevant_live_locals, boring_locals)
}
fn regions_that_outlive_free_regions<'tcx>(
num_region_vars: usize,
universal_regions: &UniversalRegions<'tcx>,
constraint_set: &OutlivesConstraintSet<'tcx>,
) -> FxHashSet<RegionVid> {
let rev_constraint_graph = constraint_set.reverse_graph(num_region_vars);
let fr_static = universal_regions.fr_static;
let rev_region_graph = rev_constraint_graph.region_graph(constraint_set, fr_static);
let mut stack: Vec<_> = universal_regions.universal_regions().collect();
let mut outlives_free_region: FxHashSet<_> = stack.iter().cloned().collect();
while let Some(sub_region) = stack.pop() {
stack.extend(
rev_region_graph
.outgoing_regions(sub_region)
.filter(|&r| outlives_free_region.insert(r)),
);
}
outlives_free_region
}
fn record_regular_live_regions<'tcx>(
tcx: TyCtxt<'tcx>,
liveness_constraints: &mut LivenessValues,
body: &Body<'tcx>,
) {
let mut visitor = LiveVariablesVisitor { tcx, liveness_constraints };
for (bb, data) in body.basic_blocks.iter_enumerated() {
visitor.visit_basic_block_data(bb, data);
}
}
struct LiveVariablesVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
liveness_constraints: &'a mut LivenessValues,
}
impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> {
fn visit_args(&mut self, args: &GenericArgsRef<'tcx>, location: Location) {
self.record_regions_live_at(*args, location);
self.super_args(args);
}
fn visit_region(&mut self, region: Region<'tcx>, location: Location) {
self.record_regions_live_at(region, location);
self.super_region(region);
}
fn visit_ty(&mut self, ty: Ty<'tcx>, ty_context: TyContext) {
match ty_context {
TyContext::ReturnTy(SourceInfo { span, .. })
| TyContext::YieldTy(SourceInfo { span, .. })
| TyContext::ResumeTy(SourceInfo { span, .. })
| TyContext::UserTy(span)
| TyContext::LocalDecl { source_info: SourceInfo { span, .. }, .. } => {
span_bug!(span, "should not be visiting outside of the CFG: {:?}", ty_context);
}
TyContext::Location(location) => {
self.record_regions_live_at(ty, location);
}
}
self.super_ty(ty);
}
}
impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> {
fn record_regions_live_at<T>(&mut self, value: T, location: Location)
where
T: TypeVisitable<TyCtxt<'tcx>>,
{
debug!("record_regions_live_at(value={:?}, location={:?})", value, location);
self.tcx.for_each_free_region(&value, |live_region| {
let live_region_vid = live_region.as_var();
self.liveness_constraints.add_location(live_region_vid, location);
});
}
}